3

I'm building a TikZ diagram in a row-by-row fashion. Each row is composed of a sequence of blobs, and the end of the row is signalled by issuing \newrow.

Here is the code I have produced so far:

\documentclass{article}

\usepackage{tikz}
\usepackage{keycommand} 

\begin{document}

\newcounter{HeightCounter}
\setcounter{HeightCounter}{0}

\newkeycommand{\blob}[left=0,right=0,minheight=0,color={}]{%
  \fill[\commandkey{color}] (\commandkey{left},\theHeightCounter) 
    rectangle (\commandkey{right},\theHeightCounter+\commandkey{minheight});
}
\newcommand{\newrow}{...}

\begin{center}
\begin{tikzpicture}[x=1mm,y=-1mm]
\blob[color=blue, left=0, right=20, minheight=6]
\blob[color=blue, left=25, right=45, minheight=8]
\blob[color=blue, left=50, right=60, minheight=7]
%\newrow
\addtocounter{HeightCounter}{8}
\blob[color=green, left=0, right=20, minheight=4]
\blob[color=green, left=25, right=35, minheight=2]
\blob[color=green, left=40, right=60, minheight=5]
%\newrow
\addtocounter{HeightCounter}{5}
\blob[color=red, left=0, right=35, minheight=4]
\blob[color=red, left=40, right=60, minheight=2]
%\newrow
\end{tikzpicture}
\end{center}

\end{document}

And here is what that code produces:

current pdf output

What I would like:

  • Each blob in a row stretches to the same height, say h, which is defined as the maximum minheight in that row.
  • The \newrow command then advances the counter HeightCounter by h.

Here is my desired output (see how each blob has stretched downward to fill the height of its respective row):

desired pdf output

Here is what I would like to type (note that the \newrow command has no parameters; it should calculate the height of the preceding row automatically):

\begin{center}
\begin{tikzpicture}[x=1mm,y=-1mm]
\blob[color=blue, left=0, right=20, minheight=6]
\blob[color=blue, left=25, right=45, minheight=8]
\blob[color=blue, left=50, right=60, minheight=7]
\newrow
\blob[color=green, left=0, right=20, minheight=4]
\blob[color=green, left=25, right=35, minheight=2]
\blob[color=green, left=40, right=60, minheight=5]
\newrow
\blob[color=red, left=0, right=35, minheight=4]
\blob[color=red, left=40, right=60, minheight=2]
\newrow
\end{tikzpicture}
\end{center}

I am generating a large number of these diagrams programmatically, so it is important to me that the height calculations are done by LaTeX, not by the human user.

The way I would program this in an ordinary programming language is:

  • Process each blob in turn, storing the respective color, left and right data for each, and accumulating the maximum of the minheight fields.
  • Upon reaching \newrow, draw all of the blobs in that row to the required height, and then advance HeightCounter by the appropriate amount.

I think that this algorithm may be quite similar to how tables are drawn by LaTeX, so maybe this problem will have quite a natural LaTeX solution.

  • 2
    If you compare this with the regular node syntax, you'll see that the largest part of the complication comes from the use of keycommand. The authors of TikZ spent so much time and effort just to provide you an extensive key control system but now you are attempting to replace it externally which, as expected, is not efficient. Also maximum height given in a particular row necessitates reading the whole row before processing it which is not feasible/possible/efficient depending on the solution path. – percusse Apr 17 '13 at 9:09
  • Thanks @percusse, that's a sensible point about the keys: I guess I'm just using keycommand out of habit. I understand the need to read the whole row before processing it, and I don't much mind it being inefficient to do so. I just hope it's possible! :) – John Wickerson Apr 17 '13 at 9:21
  • 1
    If you can give more information how the data would arrive (database?, user input? etc.) we can look for other alternatives that do not require this extra bit. – percusse Apr 17 '13 at 9:24
  • Thanks @percusse. Well, it's still early days, but I imagine the user will directly provide LaTeX code similar to what I have written above. By 'extra bit' do you mean the key-control system, or the having-to-read-the-whole-row-before-processing-it issue? – John Wickerson Apr 17 '13 at 9:31
  • 1
    The latter. Because if I think about it, there is a max operation that renders most of the height entries redundant, hence better change the design such that those redundant entries are not entered in the first place. Instead one can directly give a number and each row is placed accordingly. – percusse Apr 17 '13 at 10:01
2

Here is an idea using Key Filtering.

Another approach would be to manually deactivate certain key by using <key>/.code= but families seem more appropriate, I guess …

Code

\documentclass[tikz,convert=false]{standalone}
\providecommand{\blobset}[1]{}% (for my editor)
\providecommand{\blob}[1][]{} %
\providecommand{\newrow}{} %
\makeatletter
\def\blobset{\pgfqkeys{/blob}}
\pgfkeys{
  /utils/list to family family/.code=\edef\qrr@utils@listtofamily{#1},
  /utils/list to family/.style={
    #1/.belongs to family/.expanded=\qrr@utils@listtofamily,
  }
}
\tikzset{blob/.code=\blobset{#1}}
\blobset{
  every blob picture/.style={/tikz/x=1mm,/tikz/y=-1mm},
  % % setup
  % or keys:
  color/.style={/tikz/fill=#1},
  color/.default=black,
  left/.initial=0,
  right/.style={width={#1-(\pgfkeysvalueof{/blob/left})}},
  width/.initial=10,
  minheight/.code=\pgfmathsetmacro\blob@height{max(\blob@height,#1)},
  % our families:
  @blob@draw/.is family,
  @blob@save/.is family,
  % which key belongs to which family?
  /utils/list to family family=/blob/@blob@draw,
  /utils/list to family/.list={color, left, right, width},
  minheight/.belongs to family=/blob/@blob@save
}
\newenvironment{blobpicture}[1][]{%
  \blobset{#1}%
  \let\newrow\blob@newrow
  \let\blob\blob@
  \tikzpicture[/blob/every blob picture/.try]}{\endtikzpicture}% only LaTeX!
\def\blob@reset{\let\blob@stored\pgfutil@empty\def\blob@height{0}}
\blob@reset
\def\blob@{\pgfutil@ifnextchar[\blob@save{\blob@save[]}}
\def\blob@save[#1]{%
  \blobset{@blob@save/.activate family}%
  \pgfkeysfiltered{/blob/.cd,#1}%
  \expandafter\def\expandafter\blob@stored\expandafter{\blob@stored\blob@draw{#1}}%
}
\def\blob@draw#1{\path[every blob path/.try, blob={@blob@save/.deactivate family,#1}] ({\pgfkeysvalueof{/blob/left}},0) rectangle ++ ({\pgfkeysvalueof{/blob/width}},{\blob@height});}
\def\blob@newrow{
  \blob@stored
  \tikzset{shift={(0,\blob@height)}}%
  \blob@reset}
\makeatother

\begin{document}
\begin{blobpicture}
\blob[color=blue, left=0, right=20, minheight=6]
\blob[color=blue, left=25, right=45, minheight=8]
\blob[color=blue, left=50, right=60, minheight=7]
\newrow
\blob[color=green, left=0, right=20, minheight=4]
\blob[color=green, left=25, right=35, minheight=2]
\blob[color=green, left=40, right=60, minheight=5]
\newrow
\blob[color=red, left=0, right=35, minheight=4]
\blob[color=red, left=40, right=60, minheight=2]
\newrow
\end{blobpicture}
\end{document}

Output

enter image description here

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.