Tikz Code For The Long Haul: How To Write Maintainable And Reusable Graphics

Creating Reusable TikZ Code

When creating graphics with TikZ, it is important to think about reusability and maintainability from the beginning. Well-written TikZ code can be reused for multiple plots and data sets without modification. It also remains readable and modifiable months or years later when requirements inevitably change. This article provides best practices for creating reusable and robust TikZ graphics that stand the test of time.

Defining Custom Styles and Libraries

Rather than repeatedly specifying low-level attributes like line width, color, etc., define custom TikZ styles for your graphic elements. Styles act as variables for visual attributes, ensuring consistency and simplifying maintenance. Further structure styles into libraries grouped logically by graphic type or component.


\tikzset{
  base plot style/.style={very thick, color=black},
  data line/.style={thin, blue},
}

\tikzset{
  bar chart plots/.style={
    xbar/.style={base plot style, fill=gray},
    ybar/.style={base plot style, fill=blue},
  }
}  

Here base styles are defined, then these are reused in a custom "bar chart plots" library. This keeps related attributes together, avoids duplication, and lets styles be updated in a single place.

Parameterizing Common Attributes

Hard-coding visual attributes like line lengths, node sizes, text, etc. reduces reusability. Instead, parameterize these using TikZ commands like \pgfkeys so they can be easily changed when reusing the code.


\pgfkeys{/my chart/xbar height/.initial=2cm}
\pgfkeys{/my chart/ybar width/.initial=1cm}
\pgfkeys{/my chart/labels/.initial={}}

\begin{tikzpicture}
  \draw [xbar] (0,0) rectangle (\pgfkeysvalueof{/my chart/ybar width}, \pgfkeysvalueof{/my chart/xbar height});
  \node [above] at (current bounding box.north) 
    {\pgfkeysvalueof{/my chart/labels}}; 
\end{tikzpicture}

By parameterizing size, text, and other attributes, the same TikZ code can render completely different looking charts without modification. This simplifies reuse for varying data sets and needs.

Building Abstractions with Pic Paths

When lower-level TikZ code stabilizes, package it into custom pic paths to abstract away details. Pic syntax structures code into reusable fragments with well-defined inputs and visual output:


\pic[draw=blue, fill=yellow, angle radius=2cm, angle=30] {angle};

\begin{tikzpicture}
   \pic {angle}; 
   \pic at (2,0) {angle=45}; 
   \pic at (4,0) {angle=60};
\end{tikzpicture}

Here the visual properties of the angle graphic are defined once then reused repeatedly with simple \pic calls. Pic paths build consistency, hide complexity, and speed development of higher-level graphics.

Encapsulating Logic in Functions

For advanced abstraction of TikZ code, wrap logic and drawing commands into custom TikZ functions. Functions encapsulate the hidden details and expose only key inputs and outputs:


\tikzset{
  declare function={
    barChart(\keys){
     % Code to draw complete bar chart
     % Inputs set with \keys
    }
  }
}

\begin{tikzpicture}
  \barChart[data={\ldots}, xLabels={\ldots}]
\end{tikzpicture}  

By hiding graphical complexity inside TikZ functions, the main document code remains clean and focused on high-level structure. Functions enforce reuse, centralize maintenance, and extend functionality without changing call sites.

Enabling Extensibility with Hooks

To future-proof TikZ graphics, use hook functions to enable extension without modifying core code. Hooks define changeable code blocks that customizes can override:


\tikzset{
  bar chart/.code={
    \def\customizebar{} % Hook does nothing by default
    
    % Draw bar chart using \customizebar
  }
}

\tikzset{
  customize bar/.code={
    \draw [decoration={zigzags}]; % Customize all bars
  }
}

Hooks encapsulate changable logic so internal functions remain generic. This anticipates potential needs for tweaks, special-cases, and custom effects without modifying stable base code.

Documenting for Future Use

A well-documented TikZ graphic remains understandable and maintainable years later. Always include overview comments explaining the graphic's purpose and high-level workflow. Document key inputs, custom commands, and less obvious logic blocks.


% Draws a bar or circle graph with customizable appearance
% Usage:
%   \barchart{
%     data={...},     % Values for each bar  
%     isCircle         % Set to draw circle graph instead of bars
%   }
\def\barchart#1{

  % Process data
  \processdata{#1} 
  
  % Customize chart appearance
  \customizeappearence
  
  % Draw bars or circles
  \ifdef{\pgfkeysvalueof{/barchart/isCircle}}{
    \drawcircles % Circle graph mode 
  }{
    \drawbars % Default bar graph  
  }

}

Liberally document major logic flows, assumptions made, handy tips/tricks used, and areas likely needing customization. This guides future users and maintainers.

Testing and Validating Components

Bugs in reusable TikZ components multiply across usages. Create test cases that validate expected functioning as code evolves:


\begin{testcases}
  \validate{Line widths}{
    \tikz \draw (0,0) -- (1cm,1cm);
    \measuregraphics{currentboundingbox}{width, height}  
    \assertequals{width}{1cm}{Width matches}}  

  \validate{Label placement}{
    \barchart{data={1,2}}
    \assertnodecount{BarChartNode}{2}{Two bars drawn}
    \assertnodecount{BarLabel}{2}{Two bar labels drawn}
  }
\end{testcases}

Continuously test key assumptions and requirements as new features are added. This catches issues early and prevents adds assurance graphics remain correct over time.

Case Study: Evolving a Bar Chart Module

Let's examine a case study walking through the reusable graphics techniques above to create an evolving bar chart TikZ module:

Version 1: Basic Bar Chart


\begin{tikzpicture}
  \draw (0,0) rectangle (2cm, 5mm); 
  \draw (2cm, 0) rectangle (4cm, 1cm);
\end{tikzpicture}

The first version hard-codes a simple two-bar bar chart. To make this reusable...

Version 2: Parameterized Attributes

 
\def\barchart#1{
  \foreach \x/\h in {#1}{
    \draw (0.5*\x cm,0) rectangle (0.5*\x+0.5 cm, \h cm);
  }
}

\barchart{{1/5mm, 2/1cm}}

A macro accepts data points and draws bars. But appearance attributes remain hard-coded. To fix...

Version 3: Styles and Keys


\tikzset{
  bar width/.initial=5mm,
  bar/.style={draw=black, fill=blue!30}
}

\def\barchart#1{
  \foreach \x/\h in {#1}{
    \draw [bar] (0.5*\x cm,0) rectangle (\h cm); 
  }  
}

\barchart[bar width=1cm]{{1/5mm, 2/1cm}}

Style simplification and key-based control improves configurability and consistency.

Version 4: Pic Syntax


\pic{bar=[fill color] [draw color] height in cm};

\def\barchart#1{
  \foreach \x/\h in {#1}{
    \pic at (\x cm, 0) {bar=[blue!30] [black] \h}; 
  }
}

Encapsulation with pic promotes reuse, hides complexity, and keeps calling code cleaner.

Version 5: TikZ Function


\tikzdeclarefunction{barChart}{
  \paramkey {#1}{data}{\mydata}
  \paramkey {#1}{bar width}{\mybarwidth}
  
  \foreach \x/\h in \mydata {
    \pic at (\x*\mybarwidth cm, 0) {bar=[blue!30] [black] \h};
  }
}

\begin{tikzpicture}
  \barChart[data={1/5mm,2/1cm},bar width=5mm]
\end{tikzpicture} 

A well-designed function abstracts away graphical syntax while enabling parameterization of key attributes.

Following reusable coding principles allows TikZ graphics to evolve cleanly over time. What begins as a simple plot can grow into a flexible, configurable and clearly structured component.

Leave a Reply

Your email address will not be published. Required fields are marked *