I think I have an answer that should work, but it does not, apparently as something does not work correctly with the \pgfmathparse{} and \pgfmathresult macros. Here's what I have done:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\newcommand{\listgen}[4]% expression, start, start+step, stop
{ \foreach \n in {#2,#3,...,#4}
{ \pgfmathparse{#1}
\node at (0,\n/2) {\pgfmathresult};
\node at (-1,\n/2) {\pgfmathresult};
\node at (\n,0) {\pgfmathresult};
\node at (\n,-1) {\pgfmathresult};
}
}
\begin{document}
\begin{tikzpicture}[framed]
\listgen{\n*\n}{1}{2}{5}
\end{tikzpicture}
\begin{tikzpicture}[framed]
\foreach \n in {1,2,...,5}
{ \pgfmathparse{\n*\n}
\node at (0,\n/2) {\pgfmathresult};
\node at (-1,\n/2) {\pgfmathresult};
\node at (\n,0) {\pgfmathresult};
\node at (\n,-1) {\pgfmathresult};
}
\end{tikzpicture}
\end{document}
I defined a command to take start and stop value, the stepping and the expression. First the expression is evaluated by tikz, then it should be drawn in a node. But ehat really happens is that \pgfmathresult always returns zero. What's even more weird is that it's conditionally changed to the x-coordinate of the node. To make sure it is not my definition of \listgen, I also did the same thing manually, but still the same strange result.
Could you please run this to check wheater the error is reproducable?
Edit: Hmm, thats odd. I already used \pgfmathresult successfully, like this:
\begin{tikzpicture}[framed]
\foreach \x in {70,71,...,79}
{ \pgfmathparse{(\x-70)*5+25}
\fill[green!\pgfmathresult!black] (\x/10,1.6-\x/50) rectangle (\x/10+0.1,1.4-\x/50);
}
\end{tikzpicture}
Which should give a green staicase like thing, where the color changes with the variable through \pgfmathparse. Probably it is a bug in tikz?
Edit 2: Wohoo, it works. Thanks to Jake :D
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\newcommand{\listgen}[4]% expression, start, start+step, stop
{ \foreach \n in {#2,#3,...,#4}
{ \pgfmathsetmacro{\myresult}{#1};
\node at (0,\n/2) {\myresult};
\node at (-1,\n/2) {\myresult};
\node at (\n,0) {\myresult};
\node at (\n,-1) {\myresult};
}
}
\begin{document}
\begin{tikzpicture}[framed]
\listgen{\n*\n}{1}{2}{5}
\end{tikzpicture}
\end{document}
Edit 3: Thanks to Andrey Vihrov and Jake in this post, I was able to let it return lists as strings with brackets:
\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}
\usetikzlibrary{backgrounds}
\newcommand{\listgen}[4]% expression, start, start+step, stop
{ \gdef\myresult{}%
\foreach \n in {#2,#3,...,#4}%
{ \pgfmathsetmacro{\tikzresult}{#1}%
\ifthenelse{\n=#2}{\global\edef\myresult{(\tikzresult, }}%
{ \ifthenelse{\n=#4}{\global\edef\myresult{\myresult\tikzresult)}}%
{ \global\edef\myresult{\myresult\tikzresult, }%
}%
}%
}%
\myresult%
}
\begin{document}
\listgen{\n*\n}{1}{2}{5}\\
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\\
\begin{tikzpicture}
\draw (0,1) -- (10,1);
\node[right] at (0,0.5) {\listgen{\n*\n}{1}{2}{5}};
\draw (0,0) -- (10,0);
\end{tikzpicture}
\end{document}
which returns (1.0, 4.0, 9.0, 16.0, 25.0)
It uses TikZ
for math calculations, so it can be used inside or outside of a TikZ
environment. However it crashes if I try to put the list in {}
via \{ \}
in the commands. Does anyone know why?
The source of the difficulty is that ellipses are constructed in a particular way in TikZ. They are paths that start from the x-axis and proceed counter-clockwise around their centre. The vast majority of the time, the exact parametrisation doesn't matter. You appear to have found the one situation where it does!
In the actual question, you only want to be able to mirror the ellipse, and so draw it starting from the negative x-axis (the title of the question suggests a more flexible approach). That's actually not too hard since we can exploit the symmetry of the ellipse. The key is to provide it with a negative x-radius, since then it will start from the negative x-axis (and proceed clockwise, but we could correct for that by negating the y-radius as well). To do this, we interrupt the call from the node shape to the drawing command and flip the sign of the x-radius. The simplest way to do this is to redefine the \pgfpathellipse
macro to do the negation and then call the original macro. The following code does this.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations,shapes,decorations.markings}
\makeatletter
\let\origpgfpathellipse=\pgfpathellipse
\def\revpgfpathellipse#1#2#3{%
#2%
\pgf@xa=-\pgf@x
\origpgfpathellipse{#1}{\pgfqpoint{\pgf@xa}{0pt}}{#3}}
\makeatother
\tikzset{
reversed ellipse/.style={
ellipse,
reverse the ellipse%
},
reverse the ellipse/.code={
\let\pgfpathellipse=\revpgfpathellipse
}
}
\begin{document}
\begin{tikzpicture}
\node[ellipse,
draw,
postaction={
decorate,
decoration={
markings,
mark=at position 1 with {
\arrow[line width=5pt,blue]{>}
}
}
}
] at (0,0) {hello world};
\node[reversed ellipse,
draw,
postaction={
decorate,
decoration={
markings,
mark=at position 1 with {
\arrow[line width=5pt,blue]{>}
}
}
}
] at (0,-2) {hello world};
\end{tikzpicture}
\end{document}
Here's the result:
(the arrow got clipped, but you can see where it lies)
Best Answer
The explanation will need a bit of TeX theory.
A group is a part of the document that confines most changes made inside it only to this group itself. That is, most settings changed inside a group will be reverted to their old values once the group ends. A group is delimited by
{ … }
or\begingroup … \endgroup
. For example, a command\itshape
switches the font shape to italic. If it is used in the document, all text after that point will be set in italic shape (unless another command switches the font again). But when used inside a group —{\itshape test}
— its effect will only last to the end of the group; when the group ends, the font will be restored to whatever it was before the group was started. If an assignment or a macro definition should transcend any groups it might be in and remain in effect after the groups end, it must be prefixed with\global
(this only works for primitive TeX operations).Replacing a macro with its replacement text is called expanding the macro. TeX expands macros as it reads the input, but it does not necessarily expand arguments to commands — they are passed as they are. Therefore, in
(
\def
is the TeX primitive for defining new macros), the replacement text for\b
isb \a
, notb a
. Only when\b
is used,\a
will be expanded recursively. If it is needed that\a
is expanded at the time of\b
definition, there exists a similar primitive to\def
—\edef
, which fully (that is, recursively) expands the to-be replacement text and only then associates the text with the macro name.Now let's look at the code.
It cannot be seen directly, but the iteration code in
\foreach
is processed inside a group. Therefore, the result of\renewcommand
is immediately forgotten after each iteration, and in the end\myresult
is still empty. We can remedy this by using\global\def
instead of\renewcommand
(\renewcommand
is a complex macro and won't be affected by\global
):But now we get a different problem. After at least one iteration,
\myresult
now has the replacement textblah \myresult
. If TeX encounters\myresult
in input, it will replace the macro withblah \myresult
, which it will replace then withblah blah \myresult
, … until there is no more memory left. The problem is that we caused an infinite recursion by defining a macro that expands to itself. We wanted to use the old value of\myresult
when we redefined it, but ended up using the macro itself. We already know that we can use\edef
instead of\def
to do the former instead of the latter. Now the relevant line becomesPlain TeX defines
\xdef
to be\global\edef
. So we can shorten the code:Now it will work as planned.
With all this explained, package
etoolbox
provides the commands\xpreto<hook>{<code>}
and\xappto<hook>{<code>}
, which will globally prepend or append the expansion ofcode
to the definition of<hook>
. I should also note that spaces and new lines are significant to TeX and the code needs some comment characters.