Version con Plot funcionando
This commit is contained in:
parent
ebb0ac82fa
commit
085e99632f
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"window_geometry": "1000x700+722+83",
|
||||
"sash_pos_x": 341
|
||||
"window_geometry": "1000x700+175+111",
|
||||
"sash_pos_x": 339
|
||||
}
|
|
@ -9,6 +9,7 @@ import re
|
|||
from contextlib import contextmanager
|
||||
|
||||
from bracket_parser import BracketParser
|
||||
from interactive_results import PlotResult # 🔧 IMPORTACIÓN CORREGIDA
|
||||
from hybrid_base_types import (
|
||||
HybridCalcType, HybridHex, HybridBin, HybridDec,
|
||||
HybridIP4, HybridChr, Hex, Bin, Dec, IP4, Chr
|
||||
|
@ -111,10 +112,14 @@ class HybridEvaluationEngine:
|
|||
|
||||
def _create_plot_placeholder(self, *args, **kwargs):
|
||||
"""Crear placeholder para plots que será manejado por resultados interactivos"""
|
||||
if self.debug:
|
||||
print(f"🎯 Creando PlotResult con args: {args}, kwargs: {kwargs}")
|
||||
return PlotResult('plot', args, kwargs)
|
||||
|
||||
def _create_plot3d_placeholder(self, *args, **kwargs):
|
||||
"""Crear placeholder para plots 3D"""
|
||||
if self.debug:
|
||||
print(f"🎯 Creando PlotResult 3D con args: {args}, kwargs: {kwargs}")
|
||||
return PlotResult('plot3d', args, kwargs)
|
||||
|
||||
def _help_function(self, obj=None):
|
||||
|
@ -206,6 +211,11 @@ class HybridEvaluationEngine:
|
|||
# Evaluar en contexto SymPy
|
||||
result = self._eval_in_context(expression)
|
||||
|
||||
if self.debug:
|
||||
print(f"🔍 Resultado evaluación: {result} (tipo: {type(result)})")
|
||||
if isinstance(result, PlotResult):
|
||||
print(f" 📊 Es PlotResult: plot_type={result.plot_type}")
|
||||
|
||||
# Actualizar last_result
|
||||
self.last_result = result
|
||||
|
||||
|
@ -304,6 +314,10 @@ class HybridEvaluationEngine:
|
|||
# Si el resultado es un objeto híbrido, integrarlo con SymPy si es necesario
|
||||
if isinstance(result, HybridCalcType):
|
||||
return result
|
||||
elif isinstance(result, PlotResult):
|
||||
if self.debug:
|
||||
print(f" 📊 PlotResult detectado en eval: {result}")
|
||||
return result
|
||||
elif hasattr(result, '__iter__') and not isinstance(result, str):
|
||||
# Si es una lista/tupla, verificar si contiene objetos híbridos
|
||||
return result
|
||||
|
@ -458,6 +472,9 @@ class EvaluationResult:
|
|||
@property
|
||||
def is_interactive(self) -> bool:
|
||||
"""Determina si el resultado requiere interactividad"""
|
||||
# 🔧 CORRECCIÓN: Importar PlotResult desde el lugar correcto
|
||||
from interactive_results import PlotResult
|
||||
|
||||
return isinstance(self.result, (PlotResult, sympy.Matrix)) or \
|
||||
(isinstance(self.result, list) and len(self.result) > 3)
|
||||
|
||||
|
@ -469,21 +486,6 @@ class EvaluationResult:
|
|||
return ""
|
||||
|
||||
|
||||
class PlotResult:
|
||||
"""Placeholder para resultados de plotting"""
|
||||
|
||||
def __init__(self, plot_type: str, args: tuple, kwargs: dict):
|
||||
self.plot_type = plot_type
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __str__(self):
|
||||
return f"📊 Ver {self.plot_type.title()}"
|
||||
|
||||
def __repr__(self):
|
||||
return f"PlotResult('{self.plot_type}', {self.args}, {self.kwargs})"
|
||||
|
||||
|
||||
# Funciones de testing
|
||||
def test_evaluation_engine():
|
||||
"""Test del motor de evaluación"""
|
||||
|
@ -500,6 +502,10 @@ def test_evaluation_engine():
|
|||
"Hex[FF]",
|
||||
"IP4[192.168.1.1/24]",
|
||||
|
||||
# 🧪 PLOTS - Casos específicos para testing
|
||||
"plot(sin(x), (x, -pi, pi))",
|
||||
"plot(x**2, (x, -5, 5))",
|
||||
|
||||
# Ecuaciones
|
||||
"x + 2 = 5",
|
||||
"y**2 = 16",
|
||||
|
@ -520,6 +526,13 @@ def test_evaluation_engine():
|
|||
for test in test_cases:
|
||||
result = engine.evaluate_line(test)
|
||||
print(f"'{test}' → {result} (type: {result.result_type})")
|
||||
|
||||
# 🔍 Información adicional para plots
|
||||
if 'plot' in test:
|
||||
print(f" 🎯 Es interactivo: {result.is_interactive}")
|
||||
if isinstance(result.result, PlotResult):
|
||||
print(f" 📊 PlotResult confirmado: {result.result.plot_type}")
|
||||
|
||||
if result.info:
|
||||
print(f" Info: {result.info}")
|
||||
|
||||
|
|
|
@ -1,15 +1,30 @@
|
|||
"""
|
||||
Sistema de resultados interactivos con tags clickeables
|
||||
Sistema de resultados interactivos con tags clickeables - VERSIÓN CORREGIDA
|
||||
"""
|
||||
import tkinter as tk
|
||||
from tkinter import Toplevel, scrolledtext
|
||||
import sympy
|
||||
from typing import Any, Optional, Dict, List
|
||||
from typing import Any, Optional, Dict, List, Tuple
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
import numpy as np
|
||||
|
||||
|
||||
class PlotResult:
|
||||
"""Placeholder para resultados de plotting - DEFINICIÓN PRINCIPAL"""
|
||||
|
||||
def __init__(self, plot_type: str, args: tuple, kwargs: dict):
|
||||
self.plot_type = plot_type
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __str__(self):
|
||||
return f"📊 Ver {self.plot_type.title()}"
|
||||
|
||||
def __repr__(self):
|
||||
return f"PlotResult('{self.plot_type}', {self.args}, {self.kwargs})"
|
||||
|
||||
|
||||
class InteractiveResultManager:
|
||||
"""Maneja resultados interactivos con ventanas emergentes"""
|
||||
|
||||
|
@ -17,16 +32,17 @@ class InteractiveResultManager:
|
|||
self.parent = parent_window
|
||||
self.open_windows: Dict[str, Toplevel] = {}
|
||||
|
||||
def create_interactive_tag(self, result: Any, text_widget: tk.Text, index: str) -> Optional[str]:
|
||||
def create_interactive_tag(self, result: Any, text_widget: tk.Text, index: str) -> Optional[Tuple[str, str]]:
|
||||
"""
|
||||
Crea un tag interactivo para un resultado si es necesario
|
||||
|
||||
Returns:
|
||||
Tag name si se creó, None si no es necesario
|
||||
(tag_name, display_text) si se creó tag, None si no es necesario
|
||||
"""
|
||||
tag_name = None
|
||||
display_text = ""
|
||||
|
||||
# 🔧 CORRECCIÓN: Verificar con isinstance correcto
|
||||
if isinstance(result, PlotResult):
|
||||
tag_name = f"plot_{id(result)}"
|
||||
display_text = f"📊 Ver {result.plot_type.title()}"
|
||||
|
@ -48,37 +64,43 @@ class InteractiveResultManager:
|
|||
tag_name = f"object_{id(result)}"
|
||||
display_text = f"🔍 Ver Detalles ({type(result).__name__})"
|
||||
|
||||
if tag_name:
|
||||
# Configurar tag
|
||||
text_widget.tag_configure(
|
||||
tag_name,
|
||||
foreground="#4fc3f7",
|
||||
underline=True,
|
||||
font=("Consolas", 11, "underline")
|
||||
)
|
||||
|
||||
# Bind click event
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Button-1>",
|
||||
lambda e, r=result: self._handle_interactive_click(r)
|
||||
)
|
||||
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Enter>",
|
||||
lambda e: text_widget.config(cursor="hand2")
|
||||
)
|
||||
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Leave>",
|
||||
lambda e: text_widget.config(cursor="")
|
||||
)
|
||||
|
||||
return tag_name, display_text
|
||||
# 🔧 CORRECCIÓN: Solo crear tag si se encontró un tipo interactivo
|
||||
if tag_name and display_text:
|
||||
try:
|
||||
# Configurar tag
|
||||
text_widget.tag_configure(
|
||||
tag_name,
|
||||
foreground="#4fc3f7",
|
||||
underline=True,
|
||||
font=("Consolas", 11, "underline")
|
||||
)
|
||||
|
||||
# Bind click event
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Button-1>",
|
||||
lambda e, r=result: self._handle_interactive_click(r)
|
||||
)
|
||||
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Enter>",
|
||||
lambda e: text_widget.config(cursor="hand2")
|
||||
)
|
||||
|
||||
text_widget.tag_bind(
|
||||
tag_name,
|
||||
"<Leave>",
|
||||
lambda e: text_widget.config(cursor="")
|
||||
)
|
||||
|
||||
return (tag_name, display_text)
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error creando tag interactivo: {e}")
|
||||
return None
|
||||
|
||||
return None, str(result)
|
||||
return None
|
||||
|
||||
def _handle_interactive_click(self, result: Any):
|
||||
"""Maneja clicks en elementos interactivos"""
|
||||
|
@ -87,26 +109,32 @@ class InteractiveResultManager:
|
|||
# Si ya existe la ventana, enfocarla
|
||||
if window_key in self.open_windows:
|
||||
window = self.open_windows[window_key]
|
||||
if window.winfo_exists():
|
||||
window.lift()
|
||||
window.focus_set()
|
||||
return
|
||||
else:
|
||||
try:
|
||||
if window.winfo_exists():
|
||||
window.lift()
|
||||
window.focus_set()
|
||||
return
|
||||
else:
|
||||
del self.open_windows[window_key]
|
||||
except tk.TclError:
|
||||
del self.open_windows[window_key]
|
||||
|
||||
# Crear nueva ventana
|
||||
if isinstance(result, PlotResult):
|
||||
self._show_plot_window(result, window_key)
|
||||
elif isinstance(result, sympy.Matrix):
|
||||
self._show_matrix_window(result, window_key)
|
||||
elif isinstance(result, list):
|
||||
self._show_list_window(result, window_key)
|
||||
elif isinstance(result, dict):
|
||||
self._show_dict_window(result, window_key)
|
||||
else:
|
||||
self._show_object_window(result, window_key)
|
||||
try:
|
||||
if isinstance(result, PlotResult):
|
||||
self._show_plot_window(result, window_key)
|
||||
elif isinstance(result, sympy.Matrix):
|
||||
self._show_matrix_window(result, window_key)
|
||||
elif isinstance(result, list):
|
||||
self._show_list_window(result, window_key)
|
||||
elif isinstance(result, dict):
|
||||
self._show_dict_window(result, window_key)
|
||||
else:
|
||||
self._show_object_window(result, window_key)
|
||||
except Exception as e:
|
||||
print(f"❌ Error abriendo ventana interactiva: {e}")
|
||||
|
||||
def _show_plot_window(self, plot_result: 'PlotResult', window_key: str):
|
||||
def _show_plot_window(self, plot_result: PlotResult, window_key: str):
|
||||
"""Muestra ventana con plot matplotlib"""
|
||||
window = self._create_base_window(f"Plot - {plot_result.plot_type}", "800x600")
|
||||
self.open_windows[window_key] = window
|
||||
|
@ -124,76 +152,97 @@ class InteractiveResultManager:
|
|||
canvas.draw()
|
||||
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Toolbar para interactividad
|
||||
try:
|
||||
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
|
||||
toolbar = NavigationToolbar2Tk(canvas, window)
|
||||
toolbar.update()
|
||||
except ImportError:
|
||||
pass # Si no está disponible, continuar sin toolbar
|
||||
|
||||
except Exception as e:
|
||||
error_label = tk.Label(
|
||||
window,
|
||||
text=f"Error generando plot: {e}",
|
||||
fg="red",
|
||||
bg="#2b2b2b"
|
||||
bg="#2b2b2b",
|
||||
font=("Consolas", 12)
|
||||
)
|
||||
error_label.pack(pady=20)
|
||||
|
||||
print(f"❌ Error en plot: {e}")
|
||||
|
||||
def _create_2d_plot(self, fig, ax, args, kwargs):
|
||||
"""Crea plot 2D usando SymPy"""
|
||||
if len(args) >= 1:
|
||||
expr = args[0]
|
||||
|
||||
if len(args) >= 2:
|
||||
# Rango especificado: (variable, start, end)
|
||||
var_range = args[1]
|
||||
if isinstance(var_range, tuple) and len(var_range) == 3:
|
||||
var, start, end = var_range
|
||||
x_vals = np.linspace(float(start), float(end), 1000)
|
||||
|
||||
# Evaluar expresión
|
||||
f = sympy.lambdify(var, expr, 'numpy')
|
||||
y_vals = f(x_vals)
|
||||
|
||||
ax.plot(x_vals, y_vals, **kwargs)
|
||||
ax.set_xlabel(str(var))
|
||||
ax.set_ylabel(str(expr))
|
||||
ax.grid(True)
|
||||
ax.set_title(f"Plot: {expr}")
|
||||
else:
|
||||
# Rango por defecto
|
||||
free_symbols = list(expr.free_symbols)
|
||||
if free_symbols:
|
||||
var = free_symbols[0]
|
||||
x_vals = np.linspace(-10, 10, 1000)
|
||||
f = sympy.lambdify(var, expr, 'numpy')
|
||||
y_vals = f(x_vals)
|
||||
|
||||
ax.plot(x_vals, y_vals, **kwargs)
|
||||
ax.set_xlabel(str(var))
|
||||
ax.set_ylabel(str(expr))
|
||||
ax.grid(True)
|
||||
ax.set_title(f"Plot: {expr}")
|
||||
try:
|
||||
if len(args) >= 2:
|
||||
# Rango especificado: (variable, start, end)
|
||||
var_range = args[1]
|
||||
if isinstance(var_range, tuple) and len(var_range) == 3:
|
||||
var, start, end = var_range
|
||||
x_vals = np.linspace(float(start), float(end), 1000)
|
||||
|
||||
# Evaluar expresión
|
||||
f = sympy.lambdify(var, expr, 'numpy')
|
||||
y_vals = f(x_vals)
|
||||
|
||||
ax.plot(x_vals, y_vals, **kwargs)
|
||||
ax.set_xlabel(str(var))
|
||||
ax.set_ylabel(str(expr))
|
||||
ax.grid(True)
|
||||
ax.set_title(f"Plot: {expr}")
|
||||
else:
|
||||
# Rango por defecto
|
||||
free_symbols = list(expr.free_symbols)
|
||||
if free_symbols:
|
||||
var = free_symbols[0]
|
||||
x_vals = np.linspace(-10, 10, 1000)
|
||||
f = sympy.lambdify(var, expr, 'numpy')
|
||||
y_vals = f(x_vals)
|
||||
|
||||
ax.plot(x_vals, y_vals, **kwargs)
|
||||
ax.set_xlabel(str(var))
|
||||
ax.set_ylabel(str(expr))
|
||||
ax.grid(True)
|
||||
ax.set_title(f"Plot: {expr}")
|
||||
|
||||
except Exception as e:
|
||||
ax.text(0.5, 0.5, f"Error: {e}",
|
||||
transform=ax.transAxes, ha='center', va='center')
|
||||
ax.set_title("Error en Plot")
|
||||
|
||||
def _create_3d_plot(self, fig, args, kwargs):
|
||||
"""Crea plot 3D"""
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
if len(args) >= 3:
|
||||
expr = args[0]
|
||||
x_range = args[1] # (x, x_start, x_end)
|
||||
y_range = args[2] # (y, y_start, y_end)
|
||||
try:
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
if isinstance(x_range, tuple) and isinstance(y_range, tuple):
|
||||
x_var, x_start, x_end = x_range
|
||||
y_var, y_start, y_end = y_range
|
||||
if len(args) >= 3:
|
||||
expr = args[0]
|
||||
x_range = args[1] # (x, x_start, x_end)
|
||||
y_range = args[2] # (y, y_start, y_end)
|
||||
|
||||
x_vals = np.linspace(float(x_start), float(x_end), 50)
|
||||
y_vals = np.linspace(float(y_start), float(y_end), 50)
|
||||
X, Y = np.meshgrid(x_vals, y_vals)
|
||||
|
||||
f = sympy.lambdify([x_var, y_var], expr, 'numpy')
|
||||
Z = f(X, Y)
|
||||
|
||||
ax.plot_surface(X, Y, Z, **kwargs)
|
||||
ax.set_xlabel(str(x_var))
|
||||
ax.set_ylabel(str(y_var))
|
||||
ax.set_zlabel(str(expr))
|
||||
ax.set_title(f"3D Plot: {expr}")
|
||||
if isinstance(x_range, tuple) and isinstance(y_range, tuple):
|
||||
x_var, x_start, x_end = x_range
|
||||
y_var, y_start, y_end = y_range
|
||||
|
||||
x_vals = np.linspace(float(x_start), float(x_end), 50)
|
||||
y_vals = np.linspace(float(y_start), float(y_end), 50)
|
||||
X, Y = np.meshgrid(x_vals, y_vals)
|
||||
|
||||
f = sympy.lambdify([x_var, y_var], expr, 'numpy')
|
||||
Z = f(X, Y)
|
||||
|
||||
ax.plot_surface(X, Y, Z, **kwargs)
|
||||
ax.set_xlabel(str(x_var))
|
||||
ax.set_ylabel(str(y_var))
|
||||
ax.set_zlabel(str(expr))
|
||||
ax.set_title(f"3D Plot: {expr}")
|
||||
|
||||
except Exception as e:
|
||||
ax.text2D(0.5, 0.5, f"Error: {e}", transform=ax.transAxes)
|
||||
|
||||
def _show_matrix_window(self, matrix: sympy.Matrix, window_key: str):
|
||||
"""Muestra ventana con matriz formateada"""
|
||||
|
@ -224,24 +273,30 @@ class InteractiveResultManager:
|
|||
button_frame = tk.Frame(window, bg="#2b2b2b")
|
||||
button_frame.pack(fill=tk.X, padx=10, pady=5)
|
||||
|
||||
det_btn = tk.Button(
|
||||
button_frame,
|
||||
text="Determinante",
|
||||
command=lambda: self._show_matrix_property(matrix, "determinante", matrix.det()),
|
||||
bg="#3c3c3c",
|
||||
fg="white"
|
||||
)
|
||||
det_btn.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
if matrix.is_square:
|
||||
inv_btn = tk.Button(
|
||||
try:
|
||||
det_btn = tk.Button(
|
||||
button_frame,
|
||||
text="Inversa",
|
||||
command=lambda: self._show_matrix_property(matrix, "inversa", matrix.inv()),
|
||||
text="Determinante",
|
||||
command=lambda: self._show_matrix_property(matrix, "determinante", matrix.det()),
|
||||
bg="#3c3c3c",
|
||||
fg="white"
|
||||
)
|
||||
inv_btn.pack(side=tk.LEFT, padx=5)
|
||||
det_btn.pack(side=tk.LEFT, padx=5)
|
||||
except:
|
||||
pass # Skip si la matriz no es cuadrada
|
||||
|
||||
if matrix.is_square:
|
||||
try:
|
||||
inv_btn = tk.Button(
|
||||
button_frame,
|
||||
text="Inversa",
|
||||
command=lambda: self._show_matrix_property(matrix, "inversa", matrix.inv()),
|
||||
bg="#3c3c3c",
|
||||
fg="white"
|
||||
)
|
||||
inv_btn.pack(side=tk.LEFT, padx=5)
|
||||
except:
|
||||
pass # Skip si no es invertible
|
||||
|
||||
def _format_matrix(self, matrix: sympy.Matrix) -> str:
|
||||
"""Formatea una matriz para display"""
|
||||
|
@ -254,6 +309,8 @@ class InteractiveResultManager:
|
|||
element_str = str(matrix[i, j])
|
||||
max_width = max(max_width, len(element_str))
|
||||
|
||||
max_width = max(max_width, 8) # Mínimo 8 caracteres
|
||||
|
||||
# Construir representación
|
||||
lines = []
|
||||
lines.append("┌" + " " * (max_width * cols + cols - 1) + "┐")
|
||||
|
@ -385,54 +442,65 @@ class InteractiveResultManager:
|
|||
|
||||
def close_all_windows(self):
|
||||
"""Cierra todas las ventanas interactivas"""
|
||||
for window in self.open_windows.values():
|
||||
if window.winfo_exists():
|
||||
window.destroy()
|
||||
for window in list(self.open_windows.values()):
|
||||
try:
|
||||
if window.winfo_exists():
|
||||
window.destroy()
|
||||
except tk.TclError:
|
||||
pass
|
||||
self.open_windows.clear()
|
||||
|
||||
|
||||
# Importar PlotResult desde el motor de evaluación
|
||||
class PlotResult:
|
||||
"""Placeholder para resultados de plotting"""
|
||||
|
||||
def __init__(self, plot_type: str, args: tuple, kwargs: dict):
|
||||
self.plot_type = plot_type
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __str__(self):
|
||||
return f"📊 Ver {self.plot_type.title()}"
|
||||
|
||||
def __repr__(self):
|
||||
return f"PlotResult('{self.plot_type}', {self.args}, {self.kwargs})"
|
||||
|
||||
|
||||
# Función de testing
|
||||
def test_interactive_results():
|
||||
"""Test del sistema de resultados interactivos"""
|
||||
print("🧪 Test Interactive Results - Versión Corregida")
|
||||
print("=" * 50)
|
||||
|
||||
root = tk.Tk()
|
||||
root.title("Test Interactive Results")
|
||||
|
||||
manager = InteractiveResultManager(root)
|
||||
|
||||
# Crear widget de texto de prueba
|
||||
text_widget = tk.Text(root, height=20, width=80)
|
||||
text_widget = tk.Text(root, height=20, width=80, bg="#1e1e1e", fg="#d4d4d4")
|
||||
text_widget.pack(padx=10, pady=10)
|
||||
|
||||
# Test con PlotResult
|
||||
print("📊 Testing PlotResult...")
|
||||
plot_result = PlotResult("plot", (sympy.sin(sympy.Symbol('x')), (sympy.Symbol('x'), -10, 10)), {})
|
||||
tag_info = manager.create_interactive_tag(plot_result, text_widget, "1.0")
|
||||
if tag_info:
|
||||
tag, display = tag_info
|
||||
text_widget.insert("end", f"Plot test: {display}\n", tag)
|
||||
print(f" ✅ PlotResult tag creado: {display}")
|
||||
else:
|
||||
print(f" ❌ PlotResult tag NO creado")
|
||||
|
||||
# Test con matriz
|
||||
print("📋 Testing Matrix...")
|
||||
matrix = sympy.Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||
tag, display = manager.create_interactive_tag(matrix, text_widget, "1.0")
|
||||
text_widget.insert("end", f"Matriz test: {display}\n", tag)
|
||||
tag_info = manager.create_interactive_tag(matrix, text_widget, "2.0")
|
||||
if tag_info:
|
||||
tag, display = tag_info
|
||||
text_widget.insert("end", f"Matrix test: {display}\n", tag)
|
||||
print(f" ✅ Matrix tag creado: {display}")
|
||||
else:
|
||||
print(f" ❌ Matrix tag NO creado")
|
||||
|
||||
# Test con lista
|
||||
print("📋 Testing List...")
|
||||
long_list = list(range(20))
|
||||
tag, display = manager.create_interactive_tag(long_list, text_widget, "2.0")
|
||||
text_widget.insert("end", f"Lista test: {display}\n", tag)
|
||||
tag_info = manager.create_interactive_tag(long_list, text_widget, "3.0")
|
||||
if tag_info:
|
||||
tag, display = tag_info
|
||||
text_widget.insert("end", f"List test: {display}\n", tag)
|
||||
print(f" ✅ List tag creado: {display}")
|
||||
else:
|
||||
print(f" ❌ List tag NO creado")
|
||||
|
||||
# Test con plot
|
||||
plot_result = PlotResult("plot", (sympy.sin(sympy.Symbol('x')), (sympy.Symbol('x'), -10, 10)), {})
|
||||
tag, display = manager.create_interactive_tag(plot_result, text_widget, "3.0")
|
||||
text_widget.insert("end", f"Plot test: {display}\n", tag)
|
||||
print("\n✅ Test completado. Ventana interactiva abierta.")
|
||||
print("🔍 Haz click en los elementos para probar funcionalidad.")
|
||||
|
||||
root.mainloop()
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
# Plots Interactivos - Correcciones Implementadas
|
||||
|
||||
## 🎯 **Estado Actual**
|
||||
|
||||
✅ **Operaciones aritméticas corregidas**: `Hex[FF] + 1`, `Bin[1010] * 2`
|
||||
✅ **Asignaciones funcionando**: `z = 5`, `w = z + 3`
|
||||
🔧 **Plots interactivos**: En proceso de corrección
|
||||
|
||||
## 🔧 **Correcciones Implementadas para Plots**
|
||||
|
||||
### **1. Reorganización de PlotResult**
|
||||
- ✅ Movido `PlotResult` a `interactive_results.py` para evitar importaciones circulares
|
||||
- ✅ Importación correcta en motor de evaluación y aplicación principal
|
||||
|
||||
### **2. Detección de Resultados Interactivos**
|
||||
- ✅ Método `is_interactive` corregido en `EvaluationResult`
|
||||
- ✅ Detección de `PlotResult`, `Matrix`, y listas largas
|
||||
|
||||
### **3. Manejo de Tags Clickeables**
|
||||
- ✅ Método `create_interactive_tag()` retorna tupla `(tag, display_text)`
|
||||
- ✅ Manejo robusto de casos donde no se puede crear tag
|
||||
|
||||
## 🧪 **Scripts de Verificación**
|
||||
|
||||
### **Test Operaciones Básicas** (YA FUNCIONA ✅)
|
||||
```bash
|
||||
python debug_and_test.py
|
||||
```
|
||||
**Resultados esperados:**
|
||||
```
|
||||
✅ Hex[FF] + 1 → 256
|
||||
✅ Bin[1010] * 2 → 20
|
||||
✅ IP4[...].NetworkAddress[] → 192.168.1.0/24
|
||||
✅ z = 5 → z = 5
|
||||
✅ w = z + 3 → w = 8
|
||||
```
|
||||
|
||||
### **Test Plots Interactivos** (NUEVO)
|
||||
```bash
|
||||
python test_interactive_plots.py
|
||||
```
|
||||
**Verificará:**
|
||||
- Creación de objetos `PlotResult`
|
||||
- Evaluación de expresiones `plot()`
|
||||
- Funcionalidad del `InteractiveResultManager`
|
||||
- Flujo completo: evaluación → tag clickeable
|
||||
|
||||
### **Test Ejemplos Completos** (NUEVO)
|
||||
```bash
|
||||
python final_examples_test.py
|
||||
```
|
||||
**Ejecutará todos los ejemplos originales** que antes fallaban
|
||||
|
||||
## 🎯 **Lo que Debería Funcionar Ahora**
|
||||
|
||||
| Expresión | Estado | Resultado Esperado |
|
||||
|-----------|--------|--------------------|
|
||||
| `Hex[FF] + 1` | ✅ FUNCIONA | `256` |
|
||||
| `Bin[1010] * 2` | ✅ FUNCIONA | `20` |
|
||||
| `IP4[...].NetworkAddress[]` | ✅ FUNCIONA | `192.168.1.0/24` |
|
||||
| `z = 5` | ✅ FUNCIONA | `z = 5` |
|
||||
| `w = z + 3` | ✅ FUNCIONA | `w = 8` |
|
||||
| `plot(sin(x), (x, -pi, pi))` | 🔧 EN TEST | `📊 Ver Plot` (clickeable) |
|
||||
| `Matrix([[1, 2], [3, 4]])` | 🔧 EN TEST | `📋 Ver Matriz 2×2` (clickeable) |
|
||||
|
||||
## 🚀 **Próximos Pasos**
|
||||
|
||||
### **1. Verificar Plots**
|
||||
```bash
|
||||
# Ejecutar test específico
|
||||
python test_interactive_plots.py
|
||||
|
||||
# Si hay errores, revisar logs
|
||||
python log_viewer.py
|
||||
```
|
||||
|
||||
### **2. Test en Aplicación Completa**
|
||||
```bash
|
||||
# Iniciar aplicación
|
||||
python launcher.py
|
||||
|
||||
# Probar en interfaz:
|
||||
plot(sin(x), (x, -2*pi, 2*pi))
|
||||
Matrix([[1, 2], [3, 4]])
|
||||
```
|
||||
|
||||
### **3. Verificar Funcionalidad Clickeable**
|
||||
- Los resultados de `plot()` deberían mostrar `📊 Ver Plot`
|
||||
- Al hacer click debería abrir ventana matplotlib
|
||||
- Las matrices deberían mostrar `📋 Ver Matriz NxM`
|
||||
- Al hacer click debería mostrar matriz formateada
|
||||
|
||||
## 🔍 **Debugging si Plots No Funcionan**
|
||||
|
||||
### **Verificar Creación de PlotResult**
|
||||
```python
|
||||
from interactive_results import PlotResult
|
||||
plot_obj = PlotResult("plot", (sin(x), (x, -pi, pi)), {})
|
||||
print(plot_obj) # Debería mostrar: 📊 Ver Plot
|
||||
```
|
||||
|
||||
### **Verificar Evaluación**
|
||||
```python
|
||||
from hybrid_evaluation_engine import HybridEvaluationEngine
|
||||
engine = HybridEvaluationEngine()
|
||||
result = engine.evaluate_line("plot(sin(x), (x, -pi, pi))")
|
||||
print(f"Resultado: {result.result}")
|
||||
print(f"Tipo: {type(result.result)}")
|
||||
print(f"Es interactivo: {result.is_interactive}")
|
||||
```
|
||||
|
||||
### **Verificar Manager**
|
||||
```python
|
||||
import tkinter as tk
|
||||
from interactive_results import InteractiveResultManager
|
||||
root = tk.Tk()
|
||||
manager = InteractiveResultManager(root)
|
||||
# Test con plot_obj...
|
||||
```
|
||||
|
||||
## 📊 **Logs para Debugging**
|
||||
|
||||
Todos los errores se registran automáticamente en:
|
||||
```
|
||||
logs/mav_calc_YYYYMMDD_HHMMSS.log
|
||||
```
|
||||
|
||||
Para ver logs en tiempo real:
|
||||
```bash
|
||||
tail -f logs/mav_calc_*.log | grep -A 5 "plot\|Plot\|interactive"
|
||||
```
|
||||
|
||||
## ✅ **Checklist de Verificación**
|
||||
|
||||
- [ ] `python debug_and_test.py` pasa todos los tests ✅ (YA FUNCIONA)
|
||||
- [ ] `python test_interactive_plots.py` pasa todos los tests
|
||||
- [ ] `python final_examples_test.py` muestra 100% éxito
|
||||
- [ ] `plot(sin(x), (x, -pi, pi))` retorna `📊 Ver Plot`
|
||||
- [ ] `Matrix([[1, 2], [3, 4]])` retorna `📋 Ver Matriz 2×2`
|
||||
- [ ] La aplicación inicia sin errores: `python launcher.py`
|
||||
- [ ] Los elementos clickeables funcionan en la interfaz
|
||||
|
||||
---
|
||||
|
||||
**Estado**: ✅ Operaciones básicas corregidas, 🔧 plots interactivos en verificación
|
||||
|
||||
**Siguiente paso**: Ejecutar `python test_interactive_plots.py` y reportar resultados
|
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test específico para plots interactivos y resultados clickeables
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Agregar directorio actual al path
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from hybrid_evaluation_engine import HybridEvaluationEngine
|
||||
from interactive_results import PlotResult, InteractiveResultManager
|
||||
import sympy
|
||||
import tkinter as tk
|
||||
|
||||
|
||||
def test_plot_creation():
|
||||
"""Test de creación de objetos PlotResult"""
|
||||
print("=== Test Creación de Plots ===")
|
||||
|
||||
try:
|
||||
# Test creación básica de PlotResult
|
||||
plot_obj = PlotResult("plot", (sympy.sin(sympy.Symbol('x')), (sympy.Symbol('x'), -10, 10)), {})
|
||||
print(f"✅ PlotResult creado: {plot_obj}")
|
||||
print(f" Tipo: {type(plot_obj)}")
|
||||
print(f" String: {str(plot_obj)}")
|
||||
print(f" Plot type: {plot_obj.plot_type}")
|
||||
|
||||
# Test detección como interactivo
|
||||
from hybrid_evaluation_engine import EvaluationResult
|
||||
result = EvaluationResult(plot_obj, "expression")
|
||||
print(f"✅ is_interactive: {result.is_interactive}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error en creación de plots: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def test_plot_evaluation():
|
||||
"""Test de evaluación de expresiones plot"""
|
||||
print("\n=== Test Evaluación de Plots ===")
|
||||
|
||||
engine = HybridEvaluationEngine()
|
||||
|
||||
plot_expressions = [
|
||||
"plot(sin(x), (x, -2*pi, 2*pi))",
|
||||
"plot(x**2, (x, -5, 5))",
|
||||
"plot(cos(x), (x, 0, 2*pi))",
|
||||
"Matrix([[1, 2], [3, 4]])", # También debería ser interactivo
|
||||
]
|
||||
|
||||
for expr in plot_expressions:
|
||||
try:
|
||||
print(f"\nEvaluando: '{expr}'")
|
||||
result = engine.evaluate_line(expr)
|
||||
|
||||
if result.is_error:
|
||||
print(f" ❌ Error: {result.error}")
|
||||
else:
|
||||
print(f" ✅ Resultado: {result.result}")
|
||||
print(f" Tipo: {type(result.result)}")
|
||||
print(f" Es interactivo: {result.is_interactive}")
|
||||
|
||||
# Verificar si es PlotResult
|
||||
if isinstance(result.result, PlotResult):
|
||||
print(f" ✅ Es PlotResult!")
|
||||
print(f" Plot type: {result.result.plot_type}")
|
||||
print(f" Args: {result.result.args}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Excepción: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def test_interactive_manager():
|
||||
"""Test del manager de resultados interactivos"""
|
||||
print("\n=== Test Interactive Manager ===")
|
||||
|
||||
# Necesitamos una ventana tk para el manager
|
||||
try:
|
||||
root = tk.Tk()
|
||||
root.withdraw() # Ocultar ventana
|
||||
|
||||
manager = InteractiveResultManager(root)
|
||||
|
||||
# Crear widget de texto simulado
|
||||
text_widget = tk.Text(root)
|
||||
|
||||
# Test con PlotResult
|
||||
plot_obj = PlotResult("plot", (sympy.sin(sympy.Symbol('x')), (sympy.Symbol('x'), -10, 10)), {})
|
||||
|
||||
interactive_info = manager.create_interactive_tag(plot_obj, text_widget, "1.0")
|
||||
|
||||
if interactive_info and len(interactive_info) == 2:
|
||||
tag, display_text = interactive_info
|
||||
print(f"✅ Tag interactivo creado: '{tag}'")
|
||||
print(f" Display text: '{display_text}'")
|
||||
else:
|
||||
print(f"❌ No se creó tag interactivo: {interactive_info}")
|
||||
|
||||
# Test con Matrix
|
||||
matrix = sympy.Matrix([[1, 2], [3, 4]])
|
||||
interactive_info2 = manager.create_interactive_tag(matrix, text_widget, "2.0")
|
||||
|
||||
if interactive_info2 and len(interactive_info2) == 2:
|
||||
tag2, display_text2 = interactive_info2
|
||||
print(f"✅ Tag para matriz creado: '{tag2}'")
|
||||
print(f" Display text: '{display_text2}'")
|
||||
else:
|
||||
print(f"❌ No se creó tag para matriz: {interactive_info2}")
|
||||
|
||||
root.destroy()
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error en test de manager: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def test_full_workflow():
|
||||
"""Test del flujo completo: evaluación → resultado interactivo"""
|
||||
print("\n=== Test Flujo Completo ===")
|
||||
|
||||
try:
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
|
||||
# Simular el flujo de la aplicación
|
||||
engine = HybridEvaluationEngine()
|
||||
manager = InteractiveResultManager(root)
|
||||
text_widget = tk.Text(root)
|
||||
|
||||
# Evaluar plot
|
||||
result = engine.evaluate_line("plot(sin(x), (x, -pi, pi))")
|
||||
|
||||
print(f"Resultado evaluación: {result.result} (tipo: {type(result.result)})")
|
||||
print(f"Es interactivo: {result.is_interactive}")
|
||||
|
||||
if result.is_interactive:
|
||||
interactive_info = manager.create_interactive_tag(
|
||||
result.result, text_widget, "1.0"
|
||||
)
|
||||
|
||||
if interactive_info and len(interactive_info) == 2:
|
||||
tag, display_text = interactive_info
|
||||
print(f"✅ ÉXITO: Tag '{tag}' con texto '{display_text}'")
|
||||
else:
|
||||
print(f"❌ FALLO: No se creó tag interactivo")
|
||||
else:
|
||||
print("❌ FALLO: Resultado no marcado como interactivo")
|
||||
|
||||
root.destroy()
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error en flujo completo: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def main():
|
||||
"""Función principal de testing"""
|
||||
print("Test de Plots Interactivos - Calculadora MAV")
|
||||
print("=" * 50)
|
||||
|
||||
test_plot_creation()
|
||||
test_plot_evaluation()
|
||||
test_interactive_manager()
|
||||
test_full_workflow()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Testing completado.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue