Fundamentos de TikZ

TikZ es el lenguaje de dibujo que vive dentro de LaTeX, y su nombre ya es una advertencia. Es un acrónimo recursivo del alemán TikZ ist kein Zeichenprogramm —«TikZ no es un programa de dibujo»— que avisa desde el principio: aquí no se arrastran formas con el ratón. En su lugar se escribe \draw (0,0) -- (2,1); en el mismo archivo que el texto, y la figura se compone con las mismas fuentes y la misma calidad que el párrafo de al lado. El trato está claro: se renuncia a la comodidad y se gana precisión y reproducibilidad. Esta página lo recorre desde la primera forma hasta las coordenadas y los nodos, y luego hasta por qué la compilación se vuelve lenta y qué hacer al respecto.

Por qué TikZ insiste en que “no es un programa de dibujo”: TikZ y PGF

El nombre es una broma en la tradición GNU, y el propio manual lo reconoce: TikZ es un acrónimo recursivo en la línea de «gnu’s Not Unix», puesto ahí para avisar al lector de lo que le espera. A cambio del ratón se recibe el enfoque de TeX aplicado a las imágenes: colocación exacta, reutilización mediante macros, una rotulación acorde con el texto que la rodea. Lo que se entrega es el WYSIWYG. El manual tampoco esconde el resto de la factura y enumera en sus primeras páginas la curva de aprendizaje empinada y la recompilación que sigue a cada retoque.

Debajo, lo que traza realmente las líneas es PGF, abreviatura de «portable graphics format», y el nombre tiene un origen nítido. Su autor quería escribir macros gráficas que funcionaran igual con pdfLaTeX y con el LaTeX clásico basado en PostScript; hacía falta una capa que absorbiera las diferencias entre rutas de salida, de ahí lo de portable. Como escribir PGF crudo resulta penoso, TikZ se colocó encima como una sintaxis que una persona puede leer y teclear. Se habla de «PGF/TikZ» de un tirón, pero lo que se teclea es casi siempre el lado TikZ, y \usepackage{tikz} carga PGF junto con él.

Ambos los escribió Till Tantau. Según su propio relato, empezó a trastear con TeX siendo estudiante, de donde salió la clase de presentaciones beamer; más tarde escribió TikZ para las figuras de su tesis doctoral. La forma estándar de hacer diapositivas en LaTeX y la forma estándar de dibujar en LaTeX, dos cosas en apariencia inconexas, salieron de la misma persona. Una cifra muestra cuánto ha crecido el proyecto desde entonces: el manual de la versión 3.1.10, pgfmanual.pdf, tiene 1321 páginas. Su portada es a su vez una imagen de TikZ —árboles fractales y copos de Koch sobre un paisaje al atardecer— impresa junto al código fuente que la genera.

No hay casi nada que configurar. Una línea, \usepackage{tikz}, en el preámbulo basta para pdfLaTeX, LuaLaTeX y XeLaTeX. La única ruta que exige cuidado adicional es la que pasa por DVI: con pLaTeX o upLaTeX hay que nombrar además el controlador —normalmente dvipdfmx— como opción de clase. Este es un documento mínimo que compila.

document.tex
\documentclass{article}   % with pLaTeX: \documentclass[dvipdfmx]{jsarticle}
\usepackage{tikz}
\begin{document}
A line and a circle:
\begin{tikzpicture}
  \draw (0,0) -- (2,1);
  \draw (2.8,0.5) circle [radius=0.5cm];
\end{tikzpicture}
\end{document}

Dibujar la primera forma: el entorno tikzpicture y el punto y coma

Toda figura se dibuja dentro de \begin{tikzpicture}\end{tikzpicture}, y cada comando de dibujo termina con punto y coma ;. El entorno es la hoja sobre la que se traza una imagen, y las opciones entre corchetes tras el nombre del entorno valen para la hoja entera: [scale=2] la duplica, [thick] engrosa todas las líneas. Para una imagen que quepa en una línea no hace falta abrir el entorno: existen las formas en línea \tikz{...} y, para un solo comando, \tikz \draw ...;.

latex
% inline: one command, no environment
\tikz \draw (0,0) -- (1.5,0);

% environment: one canvas, several commands, shared options
\begin{tikzpicture}[scale=1.2, thick]
  \draw (-1.5,0) -- (1.5,0);
  \draw (0,-1.5) -- (0,1.5);
\end{tikzpicture}

Si falta un punto y coma aparece ! Package tikz Error: Giving up on this path. Did you forget a semicolon?. Lo incómodo es que el número de línea que se informa no es el de la línea rota, sino el de la siguiente. TikZ sigue tragando tokens mientras aún puedan pertenecer al camino, y solo se rinde al topar con algo que no puede pertenecer, casi siempre el \draw siguiente. Así que cuando el error señala un \draw, lo que hay que mirar es el final de la línea anterior.

Coordenadas y caminos: \draw, \fill, -- y circle

Dibujar en TikZ gira en torno al camino —una ruta que dice cómo se avanza de punto en punto— y el nombre del comando decide cómo se muestra esa ruta. \draw la traza, \fill rellena el interior de una ruta cerrada, \filldraw rellena y después traza el contorno, y \path define la ruta sin dibujar nada. Este último parece inútil, pero es la manera de dejar en silencio coordenadas y nodos para referirse a ellos más tarde. Escribe la misma lista de puntos y cambia solo el nombre del comando, y un contorno se convierte en una mancha: esa ortogonalidad es el esqueleto del diseño.

Un punto se escribe de tres maneras. En cartesianas, (x,y) cuenta por defecto en centímetros: (1,2) es 1 cm a la derecha y 2 cm hacia arriba, y las unidades pueden ir explícitas, como en (1cm,2pt). En polares, (30:1cm) se lee «1 cm en la dirección de 30°». Y una coordenada con nombre, colocada una vez con \coordinate (P) at (1,1);, se llama después simplemente (P). Conviene aprender la diferencia entre + y ++ relativos antes de que muerda: ++(1,0) avanza 1 cm a la derecha y se lleva consigo el punto actual, mientras que +(1,0) llega al mismo sitio pero deja el punto actual donde estaba. Varios ++ encadenados dan una polilínea; varios + dan radios que salen de un mismo anclaje.

Cómo avanza la ruta lo deciden las operaciones de camino. -- es una recta del punto anterior al siguiente; rectangle toma dos esquinas opuestas, circle toma un centro, y a ellos se suman ellipse, arc y grid. Las curvas salen de .. controls .. (Bézier) o de to[bend left], y una forma se cierra terminando con -- cycle, que devuelve al inicio. Los argumentos de forma se escriben hoy como pares clave-valor entre corchetes: circle [radius=10pt], ellipse [x radius=20pt, y radius=10pt], arc [start angle=0, end angle=30, radius=3mm], grid [step=.5cm]. La forma antigua con paréntesis circle (10pt) sigue funcionando, pero el código nuevo se lee mejor entre corchetes, y añadir una clave más no cuesta nada.

latex
\begin{tikzpicture}
  \draw[step=.5cm, gray, very thin] (-1.4,-1.4) grid (1.4,1.4);
  \draw (0,0) circle [radius=1cm];
  \draw (0,0) -- (30:1cm);                       % polar: 1 cm at 30 degrees
  \fill[blue!20] (0,0) rectangle (0.5,0.5);
  \draw[red] (-1.2,-1.2) -- ++(0.6,0) -- ++(0,0.6);   % ++ carries the current point
\end{tikzpicture}

Lo que sale es una sola imagen: una rejilla gris tenue con paso de 0,5 cm; un círculo de radio 1 cm centrado en el origen; un segmento corto que parte del origen a 30°; un cuadrado de 0,5 cm en el origen relleno de azul claro; y, abajo a la izquierda, un codo rojo que avanza 0,6 cm a la derecha y luego 0,6 cm hacia arriba. El color blue!20 significa «20% azul», siendo blanco el 80% restante, de ahí el tono pálido. Dos colores, como en red!50!black, se mezclan; la notación sirve igual para rellenos que para trazos.

Nodos: colocar texto y cajas, y unirlos por su nombre

Un nodo (node) coloca texto o una caja en una coordenada, con la forma \node[options] (name) at (coordinate) {contents};. En los corchetes van las opciones: draw para un borde, circle o rectangle para la forma, fill=blue!20 para el relleno, y así. Toda la gracia de la construcción está en que el nombre entre paréntesis se convierte en un asa sobre ese nodo. A partir de ahí (name) designa su posición, y un anclaje como (name.north) o (name.east) nombra un punto concreto de su contorno.

De ahí sale el patrón que se usa sin parar: colocar primero nodos con nombre y luego conectar los nombres. Unir por nombre de nodo en lugar de por coordenadas crudas significa que la línea sigue sola si más tarde se desplaza un nodo un centímetro. Y como la línea se detiene en el borde del nodo, nunca se mete dentro del círculo ni de la caja. Un nodo también puede situarse a lo largo de un camino: \draw (a) -- (b) node[midway, above] {$f$}; pone una etiqueta justo encima del punto medio del trazo, la manera habitual de nombrar una flecha.

latex
\begin{tikzpicture}
  \node (a) at (0,0)   [draw, circle, fill=blue!20] {A};
  \node (b) at (2.5,0) [draw, circle, fill=blue!20] {B};
  \draw[->] (a) -- (b) node[midway, above] {$f$};
  \draw[dashed] (a.south) -- (b.south);   % .south is an anchor on the border
\end{tikzpicture}

La imagen coloca dos nodos circulares azul claro etiquetados «A» y «B» separados 2,5 cm, traza una flecha de A a B con $f$ sobre su punto medio, y une la base de ambos círculos con una línea discontinua. Aquí hay una mina que conviene rodear: un nodo debe estar definido antes de referenciarlo. Nombrar uno que aún no se ha colocado, o escribir mal uno existente, produce ! Package pgf Error: No shape named ‘b’ is known. Los nombres se teclean mal con facilidad, así que ante ese mensaje hay que revisar la ortografía y comprobar que ese \node está realmente más arriba.

Opciones de línea y estilos reutilizables con \tikzset

El aspecto de una línea lo fijan las opciones entre corchetes: los grosores thin / thick / very thick, colores como red o blue!50, dashed y dotted, rounded corners, y las flechas -> (punta al final), <- (al inicio), <-> (en ambos extremos). Detrás de las flechas hay un atajo pragmático: TikZ considera cualquier opción desconocida que contenga un - como una especificación de flecha. Una clave mal tecleada tiene por tanto dos destinos posibles, según cómo se escriba. Sin -, TikZ avisa: ! Package pgfkeys Error: I do not know the key ‘/tikz/thikc’ and I am going to ignore it. Perhaps you misspelled it. Con un - dentro, la errata se lee como especificación de flecha y puede fallar en silencio hacia algo extraño.

OpciónSignificado
thick / very thickLíneas más gruesas (hasta ultra thick)
red, fill=blue!50Color de trazo o relleno; !n fija la intensidad y red!50!black mezcla dos
dashed / dottedLíneas discontinuas o punteadas
rounded cornersRedondear las esquinas de un camino
->, <-, <->Punta de flecha al final, al inicio o en ambos
scale=2Escalar esa imagen o camino por 2
node distance=1cmSeparación por defecto en la colocación relativa con positioning

Escribir la misma decoración una tercera vez es la señal para convertirla en estilo. Definido en el preámbulo con \tikzset{name/.style={...}}, a partir de ahí basta con pasar un nombre; y si hay que cambiar el aspecto, una línea de la definición lo cambia todo de golpe. Si el estilo solo importa dentro de una imagen, se declara en el momento en las opciones de tikzpicture. Además existen estilos que afectan a todos los elementos de un tipo —every node/.style={...}— y resultan imprescindibles en cuanto una figura como un diagrama de flujo necesita que todos sus nodos coincidan.

latex
\tikzset{help lines/.style={color=blue!50, very thin}}

\begin{tikzpicture}
  \draw[help lines] (0,0) grid (3,2);
  \draw[thick, red, ->, rounded corners] (0,0) -- (1,2) -- (3,2);
\end{tikzpicture}

Esto dibuja una rejilla azul tenue de (0,0) a (3,2) y encima una línea roja gruesa que se dobla del origen a (1,2) y luego a (3,2), con esquinas redondeadas y punta de flecha al final. Como la rejilla pasa por un estilo, cambiar very thin por thin no altera solo esta rejilla sino todas las trazadas con help lines.

Qué \usetikzlibrary hace falta de verdad

El núcleo de TikZ es deliberadamente pequeño; las partes especializadas están repartidas en bibliotecas que se cargan desde el preámbulo con \usetikzlibrary{...}, separadas por comas si son varias. Mientras una biblioteca no se cargue, su sintaxis cómoda sencillamente no existe: escribir right=of a sin positioning lleva directo al error «I do not know the key» de la sección anterior. Estas son las que de verdad se ganan su sitio el primer año.

  • arrows.meta — un conjunto rico y ajustable de puntas de flecha (-{Stealth}, -{Latex}, …). El manual marca como obsoletas las antiguas arrows y arrows.spaced; el código nuevo usa esta.
  • positioning — colocación relativa de nodos: right=of a, below=1cm of b, con node distance fijando la separación por defecto.
  • calc — aritmética de coordenadas: ($(a)+(1,0)$) es «1 cm a la derecha de a» y ($(a)!0.5!(b)$) es «el punto medio de a y b».
  • shapes — formas de nodo más allá del círculo y el rectángulo (rombos, estrellas, bocadillos), repartidas en partes como shapes.geometric.
  • decorations — decorar un camino como onda, zigzag, llave y más (decorations.pathmorphing y compañía).
  • patterns — rellenar con un patrón: tramado, líneas o puntos.
  • fit — construir automáticamente una caja que encierre justo varios nodos; cómodo para agrupar partes de una figura.
  • backgrounds — dibujar un marco o un fondo en una capa detrás de la imagen, sin chocar nunca con el primer plano.
  • matrix — alinear nodos en una rejilla (una matriz). graphdrawing hace en cambio el diseño automático, pero requiere LuaTeX.

Con arrows.meta más positioning ya basta para un diagrama de flujo utilizable. El truco está en dar coordenada solo al primer nodo y colocar los demás por relación: «a la derecha de aquel», «debajo de aquel». Si más adelante se inserta un nodo, no hay coordenadas que recalcular.

document.tex
\usepackage{tikz}
\usetikzlibrary{arrows.meta, positioning}

\begin{tikzpicture}[node distance=1cm, every node/.style={draw, rounded corners}]
  \node (start)                  {Start};
  \node (proc)  [right=of start] {Process};
  \node (end)   [right=of proc]  {End};
  \draw[-{Stealth}] (start) -- (proc);
  \draw[-{Stealth}] (proc)  -- (end);
\end{tikzpicture}

El resultado es un diagrama de flujo de izquierda a derecha: tres cajas de esquinas redondeadas con «Start», «Process» y «End», separadas 1 cm y unidas en orden por puntas Stealth afiladas. every node/.style fija de una vez el aspecto de las tres, y node distance=1cm fija la separación que emplea right=of. Poner ambos ajustes en las opciones de la imagen es justo lo que hace que una figura sea fácil de retocar después.

Por qué la compilación de TikZ es lenta y cuándo usar external o standalone

Es lenta porque el propio TeX hace la aritmética, en macros. Sumar coordenadas, convertir un ángulo en un punto, subdividir una curva de Bézier: todo eso corre dentro de la pasada de composición y no en un motor externo. Además nada se guarda en caché, así que cada \draw se recalcula desde cero en cada compilación. Con un puñado de figuras no se nota; acumula grids densas, gráficos con muchos puntos e imágenes con decenas de nodos y la espera se vuelve evidente. El propio manual lo admite pronto y cuenta las recompilaciones largas tras cambios pequeños entre los costes del enfoque de TeX.

El remedio estándar es la biblioteca external. Tras \usetikzlibrary{external} y la declaración \tikzexternalize, cada tikzpicture se escribe una sola vez en su propio PDF y queda en caché. Los nombres se asignan solos: desde main.tex salen main-figure0, main-figure1, y así. En ejecuciones posteriores, si el código de una imagen no ha cambiado, el cálculo se omite por completo y se incluye sin más el PDF terminado; cualquier retoque dispara la reconstrucción. El modo por defecto mode=convert with system call hace que LaTeX se invoque a sí mismo para fabricar las imágenes, así que hay que compilar con -shell-escape (pdflatex -shell-escape main). Sin esa opción no se genera ninguna figura: es lo primero que conviene revisar.

main.tex
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize          % caches each picture as main-figure0.pdf, main-figure1.pdf, ...

% compile with:  pdflatex -shell-escape main

El otro camino es la clase standalone. La figura pasa a un .tex aparte y se compila sola con \documentclass[tikz]{standalone}; la opción tikz carga el paquete tikz y produce un PDF de una página recortado al tamaño natural de la imagen (varios tikzpicture dan varias páginas). El documento principal se limita luego a \includegraphics{figure}. La regla práctica: external mientras la figura crezca junto al texto —el código se queda al lado de la prosa y lo único que se gana es la caché—. standalone en cuanto la figura se comparta con otros documentos o diapositivas, o vaya a retocarse decenas de veces: un documento pequeño que compila en segundos es el sitio más rápido para experimentar.

figure.tex
% compiles on its own to a one-page PDF, cropped to the picture
\documentclass[tikz]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}
  \draw[-{Stealth}, thick] (0,0) -- (2,1);
\end{tikzpicture}
\end{document}

% then in the main document:  \includegraphics{figure}