4

Prologue: this is not yet-another "how do you scale node shapes?" question, but a follow-up to the usual answers ("you kind of can, but it's awkward, and you probably shouldn't") in a specific context.


I'm working on a family of diagrams made up of 1D rows of pixels or tasks (represented mostly by rectangles):

pixel diagram

Coming from the TikZ tutorials, I started doing this using styled nodes for nearly everything: all the pixels, as well as the borders around groups of them, and deriving positioning boxes around sub-regions of the figure. This made positioning (using, e.g., the positioning and fit libraries) relatively straightforward. All the smarts for drawing paths between nodes (picking nice locations on their borders), automatically offsetting to compensate for line width (so, e.g., right = of <last node>, node distance = 0 draws rectangles with perfectly overlapping shared strokes), etc., are quite useful. It becomes incredibly convenient to be able to draw things like the blue dependence arrows seen here, just by naming the corresponding nodes, since these are just classic node to node paths.

One consequence of this is that the size of these pixel rectangles is specified using inner sep and/or minimum size.

However, coming from a graphics background where I appreciate transform stacks as an extremely useful way to write simple and composable drawing code. However, once I started trying to use relative coordinates (e.g., inner sep = 0.5, so each pixel is exactly 1 logical PGF unit in width/height, combined with /tikz/x = 3mm, /tikz/y = 3mm, to set the unit size for the whole canvas) and coordinate transforms (setting scale for a scope to slightly shrink the pixels in some region; using shift to move the location of a sub-drawing) I ran head long into the fact that TikZ applies transforms to everything but intra-node geometry.

I know about the transform shape option, but (1) that seems to be generally frowned upon (to paraphrase some answers on the subject, transforms + nodes = evil), and (2) even that does not make the simple example of defining x and y coordinate vectors to the desired size work correctly with inner sep/minimum size, since these are always interpreted as measures with absolute units.

The recommended method for drawing shapes which do conform to the transform stack seems to be to just use paths. Then, a pixel might be something like \draw[pixelstyle] (0,0) rectangle +(1,1);. This respects the transform context as expected, but loses all the nice behavior of nodes for positioning and drawing connecting paths by reference.

So my question is one of design: how would TikZ experts approach this type of drawing?

  • One has to keep in mind that nodes are actually used for text/labels. Oftentimes it does not make much sense to transform them, too, just because you change your coordinate system or scale the drawing (most times you want the text to be unrotated and the font size the same as outside the graphic). – Qrrbrbirlbel Oct 16 '13 at 3:15
  • Indeed, I do understand why nodes used for labels, etc. (likely their original purpose) should not transform with the coordinate system. However, many common idioms I see seem to involve using nodes to draw geometry (rectangles, circles, etc.) as part of a core diagram, and that's the case I'm after. Nodes provide quite a bit of power in the language which is useful well beyond labels. The essence of this question is: if not nodes (for placing primary shapes throughout a figure), then what else should I be using? – jrk Oct 16 '13 at 4:19
3

Here is a basic definition of minimum width and minimum height keys (in the /tikz name space) that each take one argument, parse it through PGFmath and when it was a unit-less input, it throws it in PGF’s coordinate system (the one that you can change with the x and the y keys). For the width the x length and for the height the y length is taken as width/height for the node. For an argument with an unit it will act as before.

This basic implemention will stop working if you change the coordinate system radically. For example, we set x=(60:1cm), then the x length of the vector (1, 0) will only be 0.5cm (we could change this by using the veclen(x, y) function to evaluate the true length of this vector). Also, the node won’t get rotated according to this which we could solve by rotating about the amount that

\pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfpointxy{1}{0}}

evaluates to (in our case, this would be 60.00003°).

Though, if the y vector is not truly orthogonal to the x vector, this would not end well. How do we transform the (previously) rectangular node then?

Code

\documentclass[tikz,png={size=200},convert=false]{standalone}
\usetikzlibrary{backgrounds}
\makeatletter
\tikzset{
  minimum width/.code=%
    \pgfmathparse{#1}%
    \ifpgfmathunitsdeclared
      \pgfset{minimum width/.expanded=+\pgfmathresult pt}%
    \else
      \pgf@process{\pgfpointxy{\pgfmathresult}{0}}%
      \pgfset{minimum width/.expanded=+\the\pgf@x}
    \fi,
  minimum height/.code=%
    \pgfmathparse{#1}%
    \ifpgfmathunitsdeclared
      \pgfset{minimum height/.expanded=+\pgfmathresult pt}%
    \else
      \pgf@process{\expandafter\pgfpointxy\expandafter{\expandafter0%
        \expandafter}\expandafter{\pgfmathresult}}% or \edef
      \pgfset{minimum height/.expanded=+\the\pgf@y}
    \fi,
  minimum size/.style={
    /tikz/minimum width={#1},
    /tikz/minimum height={#1}}
}
\makeatother
\begin{document}
\tikz[gridded]
  \node[draw, above right, inner sep=+0pt, outer sep=+0pt, minimum size=1] {};

\tikz[gridded, x=(60:1cm)]{ 
  \node[draw, above right, inner sep=+0pt, outer sep=+0pt, minimum size=1] {}
                                                   [-latex] (0,0) edge (1,0) edge (0,1);
  \pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfpointxy{1}{0}}
  \node [below]{$\pgfmathresult^\circ$};
}
\end{document}

Output

enter image description here

enter image description here

  • I was looking for more of a design discussion (how would an expert approach this, and what are the major tradeoffs) than a hack to be able to use nodes with relative sizes, but this is technically solid and useful, so I've upvoted and would be glad to accept if noting more general appears shortly. Do you have a sense of major gotchas or tradeoffs with this hack, aside from the case of non-orthogonal x/y vectors? – jrk Oct 17 '13 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.