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", "window_geometry": "1000x700+175+111",
"sash_pos_x": 341 "sash_pos_x": 339
} }

View File

@ -9,6 +9,7 @@ import re
from contextlib import contextmanager from contextlib import contextmanager
from bracket_parser import BracketParser from bracket_parser import BracketParser
from interactive_results import PlotResult # 🔧 IMPORTACIÓN CORREGIDA
from hybrid_base_types import ( from hybrid_base_types import (
HybridCalcType, HybridHex, HybridBin, HybridDec, HybridCalcType, HybridHex, HybridBin, HybridDec,
HybridIP4, HybridChr, Hex, Bin, Dec, IP4, Chr HybridIP4, HybridChr, Hex, Bin, Dec, IP4, Chr
@ -111,10 +112,14 @@ class HybridEvaluationEngine:
def _create_plot_placeholder(self, *args, **kwargs): def _create_plot_placeholder(self, *args, **kwargs):
"""Crear placeholder para plots que será manejado por resultados interactivos""" """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) return PlotResult('plot', args, kwargs)
def _create_plot3d_placeholder(self, *args, **kwargs): def _create_plot3d_placeholder(self, *args, **kwargs):
"""Crear placeholder para plots 3D""" """Crear placeholder para plots 3D"""
if self.debug:
print(f"🎯 Creando PlotResult 3D con args: {args}, kwargs: {kwargs}")
return PlotResult('plot3d', args, kwargs) return PlotResult('plot3d', args, kwargs)
def _help_function(self, obj=None): def _help_function(self, obj=None):
@ -206,6 +211,11 @@ class HybridEvaluationEngine:
# Evaluar en contexto SymPy # Evaluar en contexto SymPy
result = self._eval_in_context(expression) 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 # Actualizar last_result
self.last_result = 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 # Si el resultado es un objeto híbrido, integrarlo con SymPy si es necesario
if isinstance(result, HybridCalcType): if isinstance(result, HybridCalcType):
return result 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): elif hasattr(result, '__iter__') and not isinstance(result, str):
# Si es una lista/tupla, verificar si contiene objetos híbridos # Si es una lista/tupla, verificar si contiene objetos híbridos
return result return result
@ -458,6 +472,9 @@ class EvaluationResult:
@property @property
def is_interactive(self) -> bool: def is_interactive(self) -> bool:
"""Determina si el resultado requiere interactividad""" """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 \ return isinstance(self.result, (PlotResult, sympy.Matrix)) or \
(isinstance(self.result, list) and len(self.result) > 3) (isinstance(self.result, list) and len(self.result) > 3)
@ -469,21 +486,6 @@ class EvaluationResult:
return "" 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 # Funciones de testing
def test_evaluation_engine(): def test_evaluation_engine():
"""Test del motor de evaluación""" """Test del motor de evaluación"""
@ -500,6 +502,10 @@ def test_evaluation_engine():
"Hex[FF]", "Hex[FF]",
"IP4[192.168.1.1/24]", "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 # Ecuaciones
"x + 2 = 5", "x + 2 = 5",
"y**2 = 16", "y**2 = 16",
@ -520,6 +526,13 @@ def test_evaluation_engine():
for test in test_cases: for test in test_cases:
result = engine.evaluate_line(test) result = engine.evaluate_line(test)
print(f"'{test}'{result} (type: {result.result_type})") 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: if result.info:
print(f" Info: {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 import tkinter as tk
from tkinter import Toplevel, scrolledtext from tkinter import Toplevel, scrolledtext
import sympy import sympy
from typing import Any, Optional, Dict, List from typing import Any, Optional, Dict, List, Tuple
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np 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: class InteractiveResultManager:
"""Maneja resultados interactivos con ventanas emergentes""" """Maneja resultados interactivos con ventanas emergentes"""
@ -17,16 +32,17 @@ class InteractiveResultManager:
self.parent = parent_window self.parent = parent_window
self.open_windows: Dict[str, Toplevel] = {} 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 Crea un tag interactivo para un resultado si es necesario
Returns: 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 tag_name = None
display_text = "" display_text = ""
# 🔧 CORRECCIÓN: Verificar con isinstance correcto
if isinstance(result, PlotResult): if isinstance(result, PlotResult):
tag_name = f"plot_{id(result)}" tag_name = f"plot_{id(result)}"
display_text = f"📊 Ver {result.plot_type.title()}" display_text = f"📊 Ver {result.plot_type.title()}"
@ -48,37 +64,43 @@ class InteractiveResultManager:
tag_name = f"object_{id(result)}" tag_name = f"object_{id(result)}"
display_text = f"🔍 Ver Detalles ({type(result).__name__})" display_text = f"🔍 Ver Detalles ({type(result).__name__})"
if tag_name: # 🔧 CORRECCIÓN: Solo crear tag si se encontró un tipo interactivo
# Configurar tag if tag_name and display_text:
text_widget.tag_configure( try:
tag_name, # Configurar tag
foreground="#4fc3f7", text_widget.tag_configure(
underline=True, tag_name,
font=("Consolas", 11, "underline") foreground="#4fc3f7",
) underline=True,
font=("Consolas", 11, "underline")
# Bind click event )
text_widget.tag_bind(
tag_name, # Bind click event
"<Button-1>", text_widget.tag_bind(
lambda e, r=result: self._handle_interactive_click(r) tag_name,
) "<Button-1>",
lambda e, r=result: self._handle_interactive_click(r)
text_widget.tag_bind( )
tag_name,
"<Enter>", text_widget.tag_bind(
lambda e: text_widget.config(cursor="hand2") tag_name,
) "<Enter>",
lambda e: text_widget.config(cursor="hand2")
text_widget.tag_bind( )
tag_name,
"<Leave>", text_widget.tag_bind(
lambda e: text_widget.config(cursor="") tag_name,
) "<Leave>",
lambda e: text_widget.config(cursor="")
return tag_name, display_text )
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): def _handle_interactive_click(self, result: Any):
"""Maneja clicks en elementos interactivos""" """Maneja clicks en elementos interactivos"""
@ -87,26 +109,32 @@ class InteractiveResultManager:
# Si ya existe la ventana, enfocarla # Si ya existe la ventana, enfocarla
if window_key in self.open_windows: if window_key in self.open_windows:
window = self.open_windows[window_key] window = self.open_windows[window_key]
if window.winfo_exists(): try:
window.lift() if window.winfo_exists():
window.focus_set() window.lift()
return window.focus_set()
else: return
else:
del self.open_windows[window_key]
except tk.TclError:
del self.open_windows[window_key] del self.open_windows[window_key]
# Crear nueva ventana # Crear nueva ventana
if isinstance(result, PlotResult): try:
self._show_plot_window(result, window_key) if isinstance(result, PlotResult):
elif isinstance(result, sympy.Matrix): self._show_plot_window(result, window_key)
self._show_matrix_window(result, window_key) elif isinstance(result, sympy.Matrix):
elif isinstance(result, list): self._show_matrix_window(result, window_key)
self._show_list_window(result, window_key) elif isinstance(result, list):
elif isinstance(result, dict): self._show_list_window(result, window_key)
self._show_dict_window(result, window_key) elif isinstance(result, dict):
else: self._show_dict_window(result, window_key)
self._show_object_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""" """Muestra ventana con plot matplotlib"""
window = self._create_base_window(f"Plot - {plot_result.plot_type}", "800x600") window = self._create_base_window(f"Plot - {plot_result.plot_type}", "800x600")
self.open_windows[window_key] = window self.open_windows[window_key] = window
@ -124,76 +152,97 @@ class InteractiveResultManager:
canvas.draw() canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) 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: except Exception as e:
error_label = tk.Label( error_label = tk.Label(
window, window,
text=f"Error generando plot: {e}", text=f"Error generando plot: {e}",
fg="red", fg="red",
bg="#2b2b2b" bg="#2b2b2b",
font=("Consolas", 12)
) )
error_label.pack(pady=20) error_label.pack(pady=20)
print(f"❌ Error en plot: {e}")
def _create_2d_plot(self, fig, ax, args, kwargs): def _create_2d_plot(self, fig, ax, args, kwargs):
"""Crea plot 2D usando SymPy""" """Crea plot 2D usando SymPy"""
if len(args) >= 1: if len(args) >= 1:
expr = args[0] expr = args[0]
if len(args) >= 2: try:
# Rango especificado: (variable, start, end) if len(args) >= 2:
var_range = args[1] # Rango especificado: (variable, start, end)
if isinstance(var_range, tuple) and len(var_range) == 3: var_range = args[1]
var, start, end = var_range if isinstance(var_range, tuple) and len(var_range) == 3:
x_vals = np.linspace(float(start), float(end), 1000) var, start, end = var_range
x_vals = np.linspace(float(start), float(end), 1000)
# Evaluar expresión
f = sympy.lambdify(var, expr, 'numpy') # Evaluar expresión
y_vals = f(x_vals) f = sympy.lambdify(var, expr, 'numpy')
y_vals = f(x_vals)
ax.plot(x_vals, y_vals, **kwargs)
ax.set_xlabel(str(var)) ax.plot(x_vals, y_vals, **kwargs)
ax.set_ylabel(str(expr)) ax.set_xlabel(str(var))
ax.grid(True) ax.set_ylabel(str(expr))
ax.set_title(f"Plot: {expr}") ax.grid(True)
else: ax.set_title(f"Plot: {expr}")
# Rango por defecto else:
free_symbols = list(expr.free_symbols) # Rango por defecto
if free_symbols: free_symbols = list(expr.free_symbols)
var = free_symbols[0] if free_symbols:
x_vals = np.linspace(-10, 10, 1000) var = free_symbols[0]
f = sympy.lambdify(var, expr, 'numpy') x_vals = np.linspace(-10, 10, 1000)
y_vals = f(x_vals) f = sympy.lambdify(var, expr, 'numpy')
y_vals = f(x_vals)
ax.plot(x_vals, y_vals, **kwargs)
ax.set_xlabel(str(var)) ax.plot(x_vals, y_vals, **kwargs)
ax.set_ylabel(str(expr)) ax.set_xlabel(str(var))
ax.grid(True) ax.set_ylabel(str(expr))
ax.set_title(f"Plot: {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): def _create_3d_plot(self, fig, args, kwargs):
"""Crea plot 3D""" """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 isinstance(x_range, tuple) and isinstance(y_range, tuple): if len(args) >= 3:
x_var, x_start, x_end = x_range expr = args[0]
y_var, y_start, y_end = y_range 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) if isinstance(x_range, tuple) and isinstance(y_range, tuple):
y_vals = np.linspace(float(y_start), float(y_end), 50) x_var, x_start, x_end = x_range
X, Y = np.meshgrid(x_vals, y_vals) y_var, y_start, y_end = y_range
f = sympy.lambdify([x_var, y_var], expr, 'numpy') x_vals = np.linspace(float(x_start), float(x_end), 50)
Z = f(X, Y) y_vals = np.linspace(float(y_start), float(y_end), 50)
X, Y = np.meshgrid(x_vals, y_vals)
ax.plot_surface(X, Y, Z, **kwargs)
ax.set_xlabel(str(x_var)) f = sympy.lambdify([x_var, y_var], expr, 'numpy')
ax.set_ylabel(str(y_var)) Z = f(X, Y)
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): def _show_matrix_window(self, matrix: sympy.Matrix, window_key: str):
"""Muestra ventana con matriz formateada""" """Muestra ventana con matriz formateada"""
@ -224,24 +273,30 @@ class InteractiveResultManager:
button_frame = tk.Frame(window, bg="#2b2b2b") button_frame = tk.Frame(window, bg="#2b2b2b")
button_frame.pack(fill=tk.X, padx=10, pady=5) button_frame.pack(fill=tk.X, padx=10, pady=5)
det_btn = tk.Button( try:
button_frame, det_btn = tk.Button(
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(
button_frame, button_frame,
text="Inversa", text="Determinante",
command=lambda: self._show_matrix_property(matrix, "inversa", matrix.inv()), command=lambda: self._show_matrix_property(matrix, "determinante", matrix.det()),
bg="#3c3c3c", bg="#3c3c3c",
fg="white" 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: def _format_matrix(self, matrix: sympy.Matrix) -> str:
"""Formatea una matriz para display""" """Formatea una matriz para display"""
@ -254,6 +309,8 @@ class InteractiveResultManager:
element_str = str(matrix[i, j]) element_str = str(matrix[i, j])
max_width = max(max_width, len(element_str)) max_width = max(max_width, len(element_str))
max_width = max(max_width, 8) # Mínimo 8 caracteres
# Construir representación # Construir representación
lines = [] lines = []
lines.append("" + " " * (max_width * cols + cols - 1) + "") lines.append("" + " " * (max_width * cols + cols - 1) + "")
@ -385,54 +442,65 @@ class InteractiveResultManager:
def close_all_windows(self): def close_all_windows(self):
"""Cierra todas las ventanas interactivas""" """Cierra todas las ventanas interactivas"""
for window in self.open_windows.values(): for window in list(self.open_windows.values()):
if window.winfo_exists(): try:
window.destroy() if window.winfo_exists():
window.destroy()
except tk.TclError:
pass
self.open_windows.clear() 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 # Función de testing
def test_interactive_results(): def test_interactive_results():
"""Test del sistema de resultados interactivos""" """Test del sistema de resultados interactivos"""
print("🧪 Test Interactive Results - Versión Corregida")
print("=" * 50)
root = tk.Tk() root = tk.Tk()
root.title("Test Interactive Results") root.title("Test Interactive Results")
manager = InteractiveResultManager(root) manager = InteractiveResultManager(root)
# Crear widget de texto de prueba # 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) 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 # Test con matriz
print("📋 Testing Matrix...")
matrix = sympy.Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) matrix = sympy.Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
tag, display = manager.create_interactive_tag(matrix, text_widget, "1.0") tag_info = manager.create_interactive_tag(matrix, text_widget, "2.0")
text_widget.insert("end", f"Matriz test: {display}\n", tag) 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 # Test con lista
print("📋 Testing List...")
long_list = list(range(20)) long_list = list(range(20))
tag, display = manager.create_interactive_tag(long_list, text_widget, "2.0") tag_info = manager.create_interactive_tag(long_list, text_widget, "3.0")
text_widget.insert("end", f"Lista test: {display}\n", tag) 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 print("\n✅ Test completado. Ventana interactiva abierta.")
plot_result = PlotResult("plot", (sympy.sin(sympy.Symbol('x')), (sympy.Symbol('x'), -10, 10)), {}) print("🔍 Haz click en los elementos para probar funcionalidad.")
tag, display = manager.create_interactive_tag(plot_result, text_widget, "3.0")
text_widget.insert("end", f"Plot test: {display}\n", tag)
root.mainloop() 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()