Version con Plot funcionando

This commit is contained in:
Miguel 2025-06-01 17:20:22 +02:00
parent ebb0ac82fa
commit 085e99632f
7 changed files with 566 additions and 161 deletions

BIN
MaVCalc.lnk Normal file

Binary file not shown.

View File

@ -1,4 +1,4 @@
{
"window_geometry": "1000x700+722+83",
"sash_pos_x": 341
"window_geometry": "1000x700+175+111",
"sash_pos_x": 339
}

View File

@ -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}")

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -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")
)
# 🔧 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)
)
# 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,
"<Enter>",
lambda e: text_widget.config(cursor="hand2")
)
text_widget.tag_bind(
tag_name,
"<Leave>",
lambda e: text_widget.config(cursor="")
)
text_widget.tag_bind(
tag_name,
"<Leave>",
lambda e: text_widget.config(cursor="")
)
return tag_name, display_text
return (tag_name, display_text)
return None, str(result)
except Exception as e:
print(f"⚠️ Error creando tag interactivo: {e}")
return None
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)
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)
# 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}")
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}")
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')
try:
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)
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)
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 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)
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)
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}")
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()

147
plots_interactive_readme.md Normal file
View File

@ -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

177
test_interactive_plots.py Normal file
View File

@ -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()