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