# How can I execute a macro for every node in TikZ?

EDIT: I have started WhizzyTikZ with the goal of having WhizzyEdit work with (fairly) arbitrary TikZ code. It's good enough now that I have used it on one project.

Background:

WhizzyTeX is a system for showing live updates of a dvi (or pdf). When used with the Active-dvi viewer it also has the ability (called WhizzyEdit) to move or resize elements with the mouse. The elements must have special markup indicating their position and size via source specials. In advi changes are made with the mouse and then brought back into emacs where the position is changed in the code (based on a line number and command name). When it is recompiled the element is in the new position.

For this to work you use the \adviedit macro. You can wrap it in another macro--just tell it the name of the new macro so that WhizzyTeX knows what to change in the source. Also the macro must have a first argument something like {x=1.2,y=3.4} so that it knows how to edit the source.

My Question:

Is there some way to add the source specials to PGF/TikZ primitives so that advi would know where all TikZ nodes are and thus be able to move them? After that there might need to be some heuristics involved with how to edit the source, but I think I can handle that part. Since I know nothing about PGF/TikZ internals I don't know if it would even be possible to write source specials for "every node".

I know there is an every node style, but it doesn't seem to execute code. There is also the execute at begin scope, which can probably be used to ensure that \adviedit and TikZ use the same units, but it won't help with adding specials. In a path, execute at begin to and execute at end to might be useful, but for isolated nodes it seems useless.

Eventually I would like a package that would override (well, hopefully just append to) some internal TikZ macros allowing me to move any TikZ node and perhaps even play with Bezier curves etc.

Right now I have the first step, namely a macro that draws a node and inserts the \adviedit. It uses tkz-graph so that I don't have to parse the x=#,y=# myself.

\documentclass[12pt]{article}

\usepackage{tikz}
\usepackage{tkz-graph}

\begin{document}

\begin{tikzpicture}[x=1cm,y=1cm]
\SetVertexNoLabel
% For reference
\draw (0,0) rectangle (15,15);
% My attempt to
\def\mynode#1{%
\setedit{unit=1cm}
\Vertex[#1]{}
}
% "Turn off" WhizzyEdit
% \def\mynode#1{\Vertex[#1]{}}%
\mynode{x=8.9921,y=8.6836}
\mynode{x=7.2178,y=9.1965}
\mynode{x=6.464,y=6.6085}
\mynode{x=7.2497,y=7.8264}
\mynode{x=3.7562,y=6.9931}
\mynode{x=3.5366,y=10.3264}
\mynode{x=9.3650,y=7.0893}
\mynode{x=10.1343,y=5.4871}
\mynode{x=7.3460,y=12.1536}
\mynode{x=2.2179,y=1.5769}
\end{tikzpicture}

\end{document}


Note that labels aren't placed correctly which is why I turned them off. That's not my fault (I don't think).

-
This will probably be problematic, since TikZ works with relative coordinates inside. It then applies a transformation to get correct placement on the page. (At least, as far as I know). –  Roelof Spijker Apr 2 '12 at 15:07
This looks intriguing, but I'm having trouble getting started. I found whizzytex on debian and installed it and advi, but your code gives me problems. In particular, I can't find wedit.sty and changing to whizzytex.sty gives me configuration problems. –  Andrew Stacey Apr 2 '12 at 17:27
@AndrewStacey Oops, I copied one of the examples and cut it down. It really only needs advi.sty. @RoelofSpijker I was afraid something like that might be a problem. –  Ivan Andrus Apr 2 '12 at 18:46
Good. I got that to compile at least! –  Andrew Stacey Apr 2 '12 at 20:09
I just used this to write on top of a PDF (filling in a form). Worked really well! I added it to the relevant question (tex.stackexchange.com/a/53677/86). –  Andrew Stacey Apr 29 '12 at 12:16

I've done a little experimenting, and have some code that I hope will help you. It's not a complete solution by any means.

It appears that an advieditable macro has to be of the form \macro{x=<value>,y=<value>} for whizzytex to be able to feed the numbers back in. My first idea was simply to add a style to a \node so it looked something like \node[advi={x=<value,y=<value>}] but that didn't seem to work (maybe more experimenting would reveal a way to make this work). So I defined a wrapper around the \node command which took the coordinates at the start and then handed control over to the original \node. Because of the way that \node executes the options it is given (as in \node[draw]), there's no problem with this.

Here's the code. I'll comment on it in the code.

\documentclass[12pt]{article}
%\url{http://tex.stackexchange.com/q/50468/86}
\usepackage{tikz}

% We need to use some internal commands with @s in them for getting
% the widths of the nodes
\makeatletter
\tikzset{
% This is the workhorse style
% We do the advi stuff after the node has been placed so that we can
% get access to its width and height.  What this means is that our
% node ends up being equivalent to
% As the advi boxes are specified by lower-left corner, we anchor our
% node at the lower-left so that the given coordinate is the node
% coordinate
anchor=south west,
% The parameter #1 is of the form "x=<value>,y=<value>".  We trick
% TikZ into taking that as defining some keys in the "/tikz/advi"
% directory
#1,
% We use the values that have just been set, namely /tikz/advi/x
% and /tikz/advi/y to specify the location of the node via the
% at key.  We need to give the full path as we're currently in at
% /tikz/advi
},
% This next bit ensures that the /tikz/advi/x and y keys can be
% used to store values.
x/.initial=0,
y/.initial=0,
% This is the part that specifies the boxes in the dvi.  This is
% actually executed after the node has been processed
% As the node has been processed, we can get its width and height by
% looking at a couple of anchors.
\tikz@scan@one@point\pgfutil@firstofone(\tikzlastnode.north east)
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\tikz@scan@one@point\pgfutil@firstofone(\tikzlastnode.south west)
% We adjust the values to be multiples of ems as that's the default
% Finally, we call the \adviedit command
}
}
\makeatother

% This is the command that whizzytex will look for.
}

\begin{document}

hello world, how are you?

% We use em units as those are the defaults for advi/whizzytex.
% Presumably this could be made configurable or some wizardry used
% to ensure that the tikz coordinates and the advi coordinates
% matched.
\begin{tikzpicture}[x=1em,y=1em]
% We can even pass ordinary styles to the node:
\end{tikzpicture}

\end{document}


I don't trust trying this with the standalone class, so here's a screenshot instead.

The blue boxes and green lines are those drawn by advi. Note that they are drawn under the drawing, so are overwritten by the border of the A node and the filled region of the B node. They are draggable.

The green lines show that the coordinates are relative to something. Experimenting shows that they are relative to the (0,0) inside the picture - which is what it should be. (A quick look at the code for advi.sty shows that there is some interaction with PGF builtin which probably takes care of this bit).

(Lastly, this looks very intriguing and definitely worth learning about.)

-
I finally got some time to work on this, and I'm really excited! There's still a lot of hacking, both emacs and tikz, that I need to do before it's where I would like it, but it's showing promise. Is there a way to access /tikz/at of the last node to know how it was actually specified in the source? I'm trying to include it in the optional argument to \advi so that I can look it up more reliably, but I can't seem to get it to expand. I keep getting \pgfk@/tikz/at in the output. –  Ivan Andrus Apr 21 '12 at 20:00
@IvanAndrus Looking at the code, it would appear that you can't get exactly what was specified in the source without changing the code a bit (not a lot, though). What you can get is what the coordinate translates to in actual coordinates (so if they said at=(another node.north) you'd get the x-y values that actually corresponds to). To get that, look at the macro \tikz@node@at. –  Andrew Stacey Apr 21 '12 at 20:07
I looked at the source and figured out how to get the original values except when it's a macro like (1.3,\y), so I'll have to take a different approach anyway--at least if I want to be completely generic. –  Ivan Andrus Apr 23 '12 at 21:29