Figuras editables de draw.io para artículos académicos
Construyes figuras como objetos nativos de draw.io a partir de un script de construcción en Python (el artefacto de registro: cada coordenada, función y tamaño vive allí, para que la figura pueda regenerarse y cambiar de tema). Nunca traces píxeles, nunca rasterices texto. Detalles para cada llamada y regla: REFERENCE.md. Patrones para copiar: EXAMPLES.md.
Ejecución de las herramientas
Todo el código se envía en un solo archivo. T a continuación significa python drawio_toolkit.py:
T <herramienta> [args] # ej. T lint_drawio fig.drawio --theme theme.yaml (cualquier herramienta: --help)
T unpack ./tidyfigs # opcional: carpeta normal scripts/ assets/ examples/; luego python scripts/<herramienta>.py
En Python: import drawio_toolkit; drawio_toolkit.setup() → from drawio_kit import Diagram,
from figlib import *, from drawio_doc import Doc. Los scripts de construcción generados encuentran la biblioteca por sí mismos.
¿No hay ejecución de código disponible? Sigue el mismo método: escribe el script de construcción (o, para figuras pequeñas, el XML de draw.io directamente — REFERENCE §14) para que el usuario lo ejecute, y pídele la vista previa/salida de lint o capturas de pantalla en lugar de verlas tú mismo.
Elige el modo
| Entrada | Modo | Salida |
|---|---|---|
| imagen rasterizada para recrear | A imagen | <img>.drawio + <img>#drawio.png (300 dpi) junto a la imagen |
| prosa / sección de artículo / ecuación | B texto | 3 prototipos → el usuario elige → <nombre>.drawio |
| un .drawio existente para preparar para publicación | C mejora | <nombre>#MEJORADO.drawio + exportaciones PDF/SVG/PNG |
A o B a menudo son seguidos por C. Pregunta qué modo solo si la solicitud es genuinamente ambigua.
Reglas compartidas (todos los modos)
- Solo roles de tema. Los colores, fuentes, tamaños, trazos, opacidades provienen de un tema YAML/TOML/JSON
(
fill="primary",size="body",sw="thick",fill_opacity="tint"). Los tintes = rol existente + rol de opacidad, no un nuevo hexadecimal. ¿Necesitas un nuevo color? Añade un rol semántico (highlight,chunk_b) y díselo al usuario. Lint informa cada valor fuera del tema; los finales no tienen ninguno. - Regularizar según la intención: los pares tienen tamaños idénticos, filas/columnas un solo espacio (
row,row_widths,fit_row,column,grid_boxes), bordes compartidos una coordenada; centrar etiquetas en lo que etiquetan (x + w/2). Ignora ruido de ±1 px. - Adjuntar conectores con
src/tgt(+ fraccionesexit/entry) cada vez que una línea toca una forma;ptslista solo lo que draw.io no puede calcular (inicio libre, puntos de paso, final libre). Puntos libres solo para divisores, ejes de gráficos, vectores no conectados. - Bordes curvos (
route="curved",flex_arrow,cycle): los puntos de paso son puntos de control; la curva pasa por los puntos medios entre puntos de paso consecutivos. - Orden Z = orden de creación (los posteriores arriba): lienzo → paneles → rellenos → formas → conectores → texto
→ anotaciones. Agrupa cosas que se mueven juntas (
with d.group("azulejo")). - Identificadores estables en vértices importantes (necesarios para bordes, lint legible).
- Marcado de texto:
**negrita***cursiva*__subrayado__{rol|coloreado}\n\*; LaTeX en línea\( … \); matemáticas en pantalla medianted.equation(r"...")(MathJax nativo, editable).raw=Truepasa HTML. - Verificar mirando: después de cada construcción, ve las vistas previas PNG con tu herramienta de imágenes; los números (lint, puntuaciones, auditorías) guían, la comprobación visual decide. La vista previa aproxima draw.io: emojis = cuadrados grises, cilindros/documentos = rectángulos, sin versalitas, matemáticas mediante mathtext.
- Higiene del espacio de trabajo: los scripts de prueba, sondeos y recortes van en
<directorio_trabajo>/scratch/, nunca junto a los archivos del usuario. - Valores predeterminados académicos: fondo blanco, sin título dentro de la figura (redacta una leyenda en su lugar), ≤ 3 tonos + tintes, el color nunca es la única codificación, una familia de fuentes, ≤ 6–7 roles de tamaño, ≤ ~25 elementos de texto.
Modo A — imagen → draw.io editable
Método: medir → planificar → tematizar → script de construcción → renderizar → comparar → corregir, hasta que la vista previa coincida con la fuente en diseño. Las coordenadas son píxeles de la imagen fuente medidos en la cuadrícula real (estimar a ojo una vista redimensionada es la causa #1 de malas conversiones).
A0 Triaje (establece el esfuerzo; lee primero el ejemplo más cercano en EXAMPLES.md):
| Nivel | Parece | Técnicas principales | Iteraciones | Puntuación final |
|---|---|---|---|---|
| 1 simple | cajas, etiquetas, flechas rectas/en codo, 1–3 paneles | rect, text, edge adjunto, row | 2–3 | ≥ 0.88 |
| 2 cuadrícula/tablero | azulejos con iconos, columnas, flujos pequeños, viñetas | panel, grupos, fit_row/grid_boxes, icon, bordes ortogonales | 3–5 | ≥ 0.88 |
| 3 gráfico/geométrico | ejes, vectores, puntos, círculos, flechas onduladas, etiquetas rotadas | dot, circle, anclajes, flex_arrow, bordes curvos, rotation | 3–6 | ≥ 0.85 |
| 4 complejo | superficies 3D, mallas, fotos, dispersión densa, llamadas | surface_mesh, polygon, image_crop, scatter_*, callout, capas Z | 5–10 | ≥ 0.78 |
A1 Andamio + inspeccionar: T new_build images/fig.png [--theme user.yaml] [--scale 1] crea
images/fig_drawio_work/ (build.py, theme.yaml, NOTES.md, inspect/, iterations/, scratch/,
history.json; mantenlo). Lee inspect/summary.md y mira source.grid*.png (posiciones),
source.boxes.png/.json (bbox exactos + colores medianos — úsalos directamente), source.ocr.png/.json (texto +
tamaño de fuente: usa est_px_if_regular/bold de ajuste de ancho, elige mirando), source.palette.png
(colores → rol más cercano, ΔE). El andamio precompleta las cajas detectadas en build.py — refínalas.
Amplía cualquier región: T inspect_image zoom SRC --box x0 y0 x1 y1 --factor 3 --step 10; sondea características
finas/claras numéricamente (T inspect_image probe SRC --box … o numpy, REFERENCE §6.1). OCR lee mal y
el detector fusiona formas que se tocan — comprueba siempre visualmente.
A2 Planificar en NOTES.md: inventario región por región en orden Z. Decide por elemento:
vértice nativo (cajas, paneles, píldoras, círculos, diamantes, cilindros) · texto nativo (todo el texto, siempre) ·
edge adjunto (conexiones) · edge libre (ejes, divisores) · flex_arrow (ancho/ondulado) · dots en un
grupo (dispersión ≤ ~400) · polygon/svg_layer/surface_mesh (manchas, vigas, mallas, 3D) ·
image_crop (fotos, texturas, logotipos solo — reconstruye sus etiquetas de forma nativa encima) ·
forma de librería o icon de emoji (iconos; di cuál). Registra cada decisión no nativa para el informe.
A3 Tema: colores/fuentes del usuario → roles, mapea cada color fuente al rol más cercano; de lo contrario, los
colores dominantes de la fuente deduplicados a ≤ 6–8 roles. Agrupa los tamaños de OCR en ≤ 6–7 roles de tamaño (mismo
nivel visual ⇒ mismo rol). Familia más cercana segura para web (Helvetica/Arial; Times New Roman para serif
estilo LaTeX); google: true para Roboto/Inter. Mide el grosor del trazo en un zoom.
A4 Escribir build.py (Diagram.from_source está preconfigurado; API completa REFERENCE §2):
pid, (cx, cy, cw, ch) = d.panel(52, 110, 620, 570, "**AUTO-CODIFICACIÓN**", header_h=70, header_fill="primary",
header_color="background", title_size="heading")
for (x, y, w, h), t in zip(d.row_widths(182, 336, [97, 138, 97, 97], 62, gap=13), ["[A]", "[MASK]", "[C]", "[D]"]):
d.rect(x, y, w, h, t, fill="token", stroke="text", rounded=4, size="body", id="tok_" + t.strip("[]"))
d.rect(275, 455, 170, 62, "**Codificador**", fill="primary", color="background", rounded=4, id="enc")
d.edge([], src="enc", tgt="tok_MASK", sw="thick", exit=(.5, 0), entry=(.5, 1))
d.edge([(108, 486)], tgt="enc", entry=(0, .5)) # inicio libre, final adjunto
d.text("Dimensión 2", 365, 144, size="small", rotation=-90)
d.image_crop((49, 199, 143, 309), border="text") # foto copiada de la fuente
El contenido aleatorio (dispersión) usa una seed fija y rectángulos de exclusión alrededor de las etiquetas. > ~600 vértices →
fusiona marcas decorativas en un svg_layer. Fuentes pequeñas → --scale 2 para que el texto tenga ≥ 10 px.
A5 Iterar: T iterate images/fig_drawio_work --note "lo que cambió" = construir → renderizar → comparar → lint →
instantánea + historial. Mira iter_NN_side.png (todo: redacción, tamaños, pesos, ajuste de línea),
iter_NN_edges.png (rojo = solo fuente, cian = solo vista previa; mueve hasta que los pares se fusionen),
iter_NN_heat.png + peores celdas (amóntalas a continuación). Trabaja en pasos: (1) lienzo, paneles, cuadrículas →
(2) formas ajustadas a bbox detectados y regularizadas → (3) cada conector adjunto con puertos →
(4) roles de fuente, pesos, centrado, valign → (5) pulido de diferencias de bordes. Cambia algunas cosas relacionadas por
iteración; si la puntuación baja, revierte. Detente cuando: cada elemento del inventario esté presente (relee la
fuente región por región), lint 0 errores y sin advertencias de desbordamiento/superposición/fuera de tema, lado a lado muestre
sin desplazamiento ni texto incorrecto, puntuación estancada (< 0.005 de ganancia en 2 iteraciones). Si existe la CLI de draw.io:
una final T render_preview OUT --engine drawio.
A6 Finalizar: images/fig.drawio es la última construcción; exporta
T render_preview images/fig.drawio -o "images/fig#drawio.png" --dpi 300. La carpeta de imágenes contiene solo
fuente, .drawio, #drawio.png (+ el directorio de trabajo). Informa: rutas; nativo vs incrustado (fotos,
capas SVG, marcadores de posición de emoji); roles usados/añadidos; desviaciones conocidas; errores tipográficos de la fuente mantenidos;
cómo cambiar el tema (editar theme.yaml → python build.py) y reescalar.
Modo B — texto → tres prototipos de figura editables
Lee el pasaje, inventa sus afirmaciones, construye tres familias de figuras diferentes, revísalas, presenta una hoja lado a lado; el usuario elige; tú finalizas.
Ubicación de salida: archivo drafts/methods.md → drafts/methods_figures/; texto pegado →
./figures/<slug>/; entrada multi-sección/larga → una subcarpeta por pasaje p1_<slug>/ …; una
carpeta nombrada por el usuario → exactamente esa (--out-dir). Dile al usuario la ruta. Un tema compartido por todos
los pasajes (--theme o edita theme.yaml en la raíz de salida).
B1 Andamio + analizar: T new_figures drafts/methods.md [--theme t.yaml] [--split|--whole] [--passages 1,3] o T new_figures --text "<pasaje>" --name rag_pipeline. Imprime por pasaje: recuento
de palabras, ecuaciones, pistas de estructura, tres familias sugeridas. ≤ 350 palabras sin encabezados = un
pasaje. ¿Sin estructura digna de figura (pura narrativa)? Dilo en lugar de forzar figuras.
B2 Inventario (NOTES.md): entidades, pasos ordenados (con sus verbos), relaciones (dirección + verbo), cantidades con unidades, calificadores, conclusiones — cada una con una cita corta. Confirma las familias (REFERENCE §7): predeterminado = tres diseños de la estructura dominante (detallado / resumen compacto / lente alternativa); segunda estructura fuerte → dos + uno; ecuaciones → el trío de ecuaciones a menos que sea incidental. Las tres deben diferir en topología (carriles / pila / radial / matriz / gráfico / placa), no en estilo. Para pasajes matemáticos, científicos, algorítmicos prefiere demostraciones activas (cálculo matricial poblado, espacios de coordenadas/métricos continuos, placas Bayesianas, DAG causales) sobre tarjetas de viñetas estáticas.
B3 Escribir build.py — tres constructores, cada uno recibe un Diagram nuevo de su tamaño de lienzo:
from figlib import *
INFERRIDO = ["v1: las calificaciones ordinales interpretan la redacción cualitativa del pasaje"] # informado al usuario
TERMINOS_PERMITIDOS = ["capa"] # palabras estructurales, no afirmaciones
IGNORAR_LINT = [] # advertencias aceptadas a propósito (subcadena)
def v1(d): # tubería de carril
carril(d, 20, 20, 1060, 175, "Indexación fuera de línea")
cadena(d, ["Informes de inspección\n(escaneados)", "OCR\na texto", "Fragmentación\nsemántica"], 80, 78, 140, 60,
shapes=["documento", None, None], ids=["rep", "ocr", "chk"])
VARIANTES = [dict(key="v1", name="tuberia_carriles", size=(1100, 400), build=v1,
about="una línea para la hoja", caption="Leyenda borrador en las palabras del pasaje."), ...]
Reglas: solo roles de tema, misma categoría = mismo estilo en las tres; los pares comparten tamaños y un espacio
(ayudantes, no números ajustados a mano); conectores adjuntos, retroalimentación discontinua/secundaria; ≤ ~25 elementos de texto,
< ~150 vértices (si no, divide en dos figuras); sin título dentro de la figura — escribe caption; etiquetas en la
redacción del pasaje (acorta por eliminación, no con sinónimos; mantén calificadores, dígitos, unidades, acrónimos tal como
están escritos). Dispositivos interpretativos (calificaciones, fronteras, "mejor ajuste", ordenaciones de ejes, hechos matemáticos no en el
texto) solo si están listados en INFERRIDO.
B4 Prototipo, inspeccionar, corregir (≥ 2 rondas): T prototype <directorio pasaje> [--only v2] --note "…" construye
los tres, renderiza, hace lint, ejecuta la comprobación de fidelidad, escribe prototypes.png/.md, registra err/warn/miss.
Mira cada PNG y la hoja. Corrige cada advertencia de lint o añade un IGNORAR_LINT deliberado; resuelve
cada palabra NO-EN-PASAJE (reformula con el término del pasaje · TERMINOS_PERMITIDOS si es estructural · INFERRIDO
si es interpretación). Comprueba lo que lint no puede: flechas que cruzan etiquetas, esquinas abarrotadas, jerarquía débil,
desequilibrio de espacio en blanco, dos prototipos demasiado similares, la dirección de cada flecha contra el inventario.
Termina en 0/0/0 (o advertencias aceptadas) y limpio a tamaño completo.
B5 Presentar: muestra prototypes.png; por prototipo una línea sobre su énfasis, su leyenda borrador, sus
elementos INFERRIDOS; señala rarezas de la fuente (errores tipográficos, nombres inconsistentes) en lugar de corregir en silencio. Pregunta
al usuario que elija (o solicite cambios / una combinación → edita build.py, vuelve a ejecutar).
B6 Finalizar: T finalize <directorio pasaje> --pick v2 [--name rag_pipeline] [--clean] → <nombre>.drawio
(+ .png) y CHOSEN.md (leyenda, inferido). --clean elimina los otros prototipos pero mantiene _work/.
Ofrece el modo C para pulido específico de revista.
Modo C — mejorar un .drawio para publicación
Una pasada deliberada: entender el trabajo de la figura → medir al tamaño de impresión → cambiarla para que sirva ese trabajo → verificar → exportar. Nunca edites antes de la entrevista.
C1 Iniciar: T start_enhance ruta/FIG.drawio [--source-image] [--text] [--artifacts DIR] [--theme].
Descubre contexto (directorio de trabajo del modo A: imagen fuente, build.py, theme, NOTES; carpeta del pasaje del modo B:
passage.md, build.py VARIANTES, CHOSEN.md, caption, INFERRED), detecta ediciones manuales después de la generación,
recomienda una ruta, audita "antes", escribe <stem>_enhance_work/ (context.md, before_audit.md,
brief.yaml, questions.md, theme.yaml, build_enhanced.py si
…
[truncado para traducción]