13

I couldn't really think of a reasonable title for this question; but anyhow, here goes:

I saw a very interesting question and solution today here:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\thispagestyle{empty}
\usetikzlibrary{decorations.pathmorphing,shapes}
\tikzset{
  treetop/.style = {
    decoration={random steps, segment length=0.4mm},
    decorate
  },
  trunk/.style = {
    decoration={random steps, segment length=2mm, amplitude=0.2mm},
    decorate
  }
}

\begin{tikzpicture}
\foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
  \fill [brown!\f!black, trunk] (0,0) ++(-\w/2,0) rectangle +(\w,-3);
}
\foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
   \fill [green!\f!black, treetop] ellipse (\n/1.5 and \n);
}
\end{tikzpicture}
\end{document}

From this solution I would like to know if it was possible to copy this diagram n times by simply referring to the code shown. For example, if I was drawing a field, drawn as a simple horizontal line:

\begin{tikzpicture}
\draw(0,0) -- (10,0);
\end{tikzpicture}

Could I then repeat the tree drawn, say 4 times along this line to represent a portion of a forest, scaled accordingly? For example:

Obviously these can be created by a simple for loop, however, I guess I'm just trying to find a way of re-applying the code for the tree numerous times.

2
  • 2
    You can save the picture in a savebox and reuse the content of the saved box later on. Personally, I'd be against that idea because generating randomly shaped trees is much nicer!
    – user10274
    Mar 6 '13 at 19:11
  • could you provide an example :)
    – KatyB
    Mar 6 '13 at 19:15
14

As Marc van Dongen commented you could save the picure in a \savebox and reuse that. But, then all the pictures will be identical. Instead, you can define a command for the tikzpicture and reuse it which yields a different tree for each instance, or define a macro to be useable within a \tikzpicture environment.

1. Reuse entire tikzpicture:

enter image description here

Notes:

  • If you wish to reuse the same \Tree code within a tikzpicture then define a macro that only contains the two foreach loops, and either use a `scope to shift each instance to the right, or provide a parameter which controls where the drawing is done.

Code:

\documentclass{article}
\usepackage{tikz}

\thispagestyle{empty}
\usetikzlibrary{decorations.pathmorphing,shapes}
\tikzset{
  treetop/.style = {
    decoration={random steps, segment length=0.4mm},
    decorate
  },
  trunk/.style = {
    decoration={random steps, segment length=2mm, amplitude=0.2mm},
    decorate
  }
}

\newcommand*{\Tree}{%
\begin{tikzpicture}
\foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
  \fill [brown!\f!black, trunk] (0,0) ++(-\w/2,0) rectangle +(\w,-3);
}
\foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
   \fill [green!\f!black, treetop] ellipse (\n/1.5 and \n);
}
\end{tikzpicture}}%

\begin{document}
\Tree \Tree \Tree \Tree
\end{document}

2. Using scope:

If you wish to reuse the same \Tree code within a tikzpicture you could define a macro that only contains the two foreach loops, and use a `scope to shift each instance to the right

Code:

\documentclass{article}
\usepackage{tikz}

\thispagestyle{empty}
\usetikzlibrary{decorations.pathmorphing,shapes}
\tikzset{
  treetop/.style = {
    decoration={random steps, segment length=0.4mm},
    decorate
  },
  trunk/.style = {
    decoration={random steps, segment length=2mm, amplitude=0.2mm},
    decorate
  }
}

\newcommand*{\Tree}{%
    \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
      \fill [brown!\f!black, trunk] (0,0) ++(-\w/2,0) rectangle +(\w,-3);
    }
    \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
       \fill [green!\f!black, treetop] ellipse (\n/1.5 and \n);
    }
}%

\begin{document}
\begin{tikzpicture}
    \Tree 

\begin{scope}[xshift=2cm]
    \Tree 
\end{scope}

\begin{scope}[xshift=4cm]
    \Tree 
\end{scope}

\begin{scope}[xshift=6cm]
    \Tree
\end{scope}
\end{tikzpicture}
\end{document}

3. Parametrized Version:

Another way of reusing the same code within a tikzpicture would be to define a macro which contains the two foreach loops, and takes a parameter which controls where the drawing is done.

Code:

\documentclass{article}
\usepackage{tikz}

\thispagestyle{empty}
\usetikzlibrary{decorations.pathmorphing,shapes}
\tikzset{
  treetop/.style = {
    decoration={random steps, segment length=0.4mm},
    decorate
  },
  trunk/.style = {
    decoration={random steps, segment length=2mm, amplitude=0.2mm},
    decorate
  }
}

\newcommand*{\Tree}[2]{%
    % #1 = origin coordinate
    \begin{scope}[xshift=#1 cm, yshift=#2 cm]
        \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
          \fill [brown!\f!black, trunk] (0,0) ++(-\w/2,0) rectangle +(\w,-3);
        }
        \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
           \fill [green!\f!black, treetop] ellipse (\n/1.5 and \n);
        }
    \end{scope}
}%

\begin{document}
\begin{tikzpicture}
    \Tree{0}{0}
    \Tree{2}{0}
    \Tree{4}{0} 
    \Tree{6}{0}
\end{tikzpicture}
\end{document}

4. Fancy Version

If you are parametrizing the macro, might as well add optional parameters to be able to control the draw options for the treetop and trunk as well:

enter image description here

Notes:

  • My color choices were based on Pandora, but I have been told that on Earth, well at least in the UK :-), trees in nature do not exhibit these kind of colors. Perhaps someone who can chose more aesthetically pleasing colors can edit the choices here.

Code:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}

\thispagestyle{empty}
\usetikzlibrary{decorations.pathmorphing,shapes}
\tikzset{
  treetop/.style = {
    decoration={random steps, segment length=0.4mm},
    decorate
  },
  trunk/.style = {
    decoration={random steps, segment length=2mm, amplitude=0.2mm},
    decorate
  }
}

\NewDocumentCommand{\Tree}{%
    O{green!\f!black}% #1 = tree top options
    O{brown!\f!black}% #2 = trunk options
    m% #3 = xshift
    m% #4 = yshift
    }{%
    \begin{scope}[xshift=#3 cm, yshift=#4 cm]
        \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
          \fill [#2, trunk] (0,0) ++(-\w/2,0) rectangle +(\w,-3);
        }
        \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
           \fill [#1, treetop] ellipse (\n/1.5 and \n);
        }
    \end{scope}
}%

\begin{document}
\begin{tikzpicture}
    \Tree{0}{0}
    \Tree[orange!\f!black][gray!\f!blue]{2}{0}
    \Tree[olive!\f!cyan][orange!\f!violet]{4}{0} 
    \Tree[orange!\f!red][brown!\f!black]{6}{0}
\end{tikzpicture}
\end{document}
3
  • This is brilliant! I prefer the first version, though ;).
    – cfr
    Nov 18 '14 at 2:14
  • @cfr: :-) You obviously don't live in a place where you have such colorful trees!! Nov 18 '14 at 2:16
  • Or I am just very boring. The pic version looks nice, too.
    – cfr
    Nov 18 '14 at 2:24
7

All previous answers were (and still are) valid with TiKZ versions previous to v3.0. But TikZ 3.0 introduced a new tool called pics (more information in pgfmanual's section 18. Pics: Small Pictures on Paths) which can be used to declare and reuse complex figures without having to use new shapes.

With this tool, any group of commands can be declared inside a pic

   my tree/.pic={
     \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
       \fill [brown!\f!black, trunk] (-\w/2,0) rectangle +(\w,3);
     }
     \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
       \fill [green!\f!black, treetop](0,3) ellipse (\n/1.5 and \n);
     }
   }

and used afterwards with drawing commands like \pic at (x,y) {my tree}; or \path (x,y) pic {my tree};.

If pics are declared with arguments, another declaration syntax is needed:

   pics/second tree/.style 2 args={
    code={
         \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
             \fill [#2, trunk] (-\w/2,0) rectangle +(\w,3);
          }
          \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
             \fill [#1, treetop](0,3) ellipse (\n/1.5 and \n);
          }
       }
   }

An example using both syntax could be:

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{decorations.pathmorphing,calc,shapes,shapes.geometric,patterns}
\begin{document}

\tikzset{treetop/.style = {decoration={random steps, segment length=0.4mm},decorate},trunk/.style = {decoration={random steps, segment length=2mm, amplitude=0.2mm},decorate}}

\tikzset{
   my tree/.pic={
     \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
       \fill [brown!\f!black, trunk] (-\w/2,0) rectangle +(\w,3);
     }
     \foreach \n/\f in {1.4/40,1.2/50,1/60,0.8/70,0.6/80,0.4/90} {
       \fill [green!\f!black, treetop](0,3) ellipse (\n/1.5 and \n);
     }
   }
}

\begin{tikzpicture}
\pic at (2,0) {my tree};
\draw (4,0) pic {my tree};
\path (6,0) pic {second tree={red!\f}{purple!\f}};
\pic at (0,0) {second tree={orange!\f!black}{gray!\f!blue}};
\end{tikzpicture}


\end{document}

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.