28

If I have two tikzpictures drawn:

\documentclass{article}
\usepackage[margin = 1in]{geometry}
\usepackage{tikz}
\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}}

\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{tikzpicture}
\shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
\end{tikzpicture}

\end{document}

enter image description here

How could I use the first tikz picture within the second? Can I define the first picture as some variable and then place this variable within the second picture and have the option of defining its exact location (x,y) and its size? For example, if I wanted to place the tree in the middle of the rectangle (5,5) but make the size of the tree half its current size. How would I do this

jub0bs
  • 58,916
KatyB
  • 2,871
  • Can it be a duplicate of http://tex.stackexchange.com/questions/37823/how-to-get-consistent-positioning-for-a-node-with-usebox-containing-a-tikzpict – percusse Jul 31 '13 at 08:01
  • How about using the background canvas via ´\begin{scope}[background] ... \end{scope}´ for the second image? (I am still a beginner.) – Jan Apr 03 '18 at 09:53

4 Answers4

42

TiKZ 3.0.0 introduces pic a "short picture" which can be inserted in any place of a tikzpicture. A possible solution with 'pic' would be:

\documentclass{standalone}
\usepackage[margin = 1in]{geometry}
\usepackage{tikz}
\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}
\shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
\pic at (2,2) {my tree};
\pic at (4,2.5) {my tree};
\pic at (6,1.75) {my tree};
\end{tikzpicture}

\end{document}

enter image description here

Ignasi
  • 136,588
19

I would define a specific key for the tree and one for the position:

% to get the positions of last x,y
\newdimen\xval
\newdimen\yval

\pgfkeys{/tikz/.cd,
   at/.initial={(0,0)},
   at/.get=\coordpos,
   at/.store in=\coordpos,   
   my tree/.code={
     \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
       \fill [brown!\f!black, trunk] \coordpos ++(-\w/2,0) rectangle +(\w,-3);
     }
     \pgfgetlastxy{\xval}{\yval};
     \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](\xval,\yval) ellipse (\n/1.5 and \n);
     }
   }
}

so that in the final picture you can use:

\begin{tikzpicture}
\shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
\node[at={(2.5,5)},my tree]{};
\node[at={(5,5)},my tree]{};
\node[at={(7.5,5)},my tree]{};
\end{tikzpicture}

The complete code:

\documentclass{article}
\usepackage[margin = 1in]{geometry}
\usepackage{tikz}
\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}}

% to get the positions of last x,y
\newdimen\xval
\newdimen\yval

\pgfkeys{/tikz/.cd,
   at/.initial={(0,0)},
   at/.get=\coordpos,
   at/.store in=\coordpos,   
   my tree/.code={
     \foreach \w/\f in {0.3/30,0.2/50,0.1/70} {
       \fill [brown!\f!black, trunk] \coordpos ++(-\w/2,0) rectangle +(\w,-3);
     }
     \pgfgetlastxy{\xval}{\yval};
     \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](\xval,\yval) ellipse (\n/1.5 and \n);
     }
   }
}

\begin{tikzpicture}
\shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
\node[at={(2.5,5)},my tree]{};
\node[at={(5,5)},my tree]{};
\node[at={(7.5,5)},my tree]{};
\end{tikzpicture}

\end{document}

The result:

enter image description here

  • 1
    +1 Much more elegant solution than mine. I need to get up to speed on pgfkeys! – jub0bs Jul 31 '13 at 08:17
  • @Jubobs: definitely ;) – Claudio Fiandrino Jul 31 '13 at 08:37
  • +100 This is brilliant. You just helped me save hundreds of lines of code as I had lots of variations on the same image throughout a document. I don't know if it's correct or not, but specifying coordinates within a node works as well. – Robbie Oct 31 '16 at 05:13
6

Let us define a newcommand:

\newcommand\myfig[2]{%
    \begin{scope}[xshift=#1cm,yshift=#2cm]
        \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}
}

And use it like this:

\documentclass{article}
\usepackage[margin = 1in]{geometry}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing,calc,shapes,shapes.geometric,patterns}

\newcommand\myfig[2]{%
    \begin{scope}[xshift=#1cm,yshift=#2cm]
        \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}
\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}
    \myfig{0}{0}
\end{tikzpicture}

\begin{tikzpicture}
    \shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
    \myfig{2.5}{5}
    \myfig{5}{5}
    \myfig{7.5}{5}    
\end{tikzpicture}

\end{document}

enter image description here

  • I think, this is very elegant, too. And---just in case---it solved my actual problem very well! Thank you! – Jan Apr 03 '18 at 09:56
5

Yes, it can be done with a pgfonlayer environment within the tikzpicture and a new command (called \treedrawing below) that takes as argument the coordinates (of the form x,y) of the tree and draws it there. Just make sure to call \treedrawing after the pgfonlayer environment, or your trees will be behind the background.

enter image description here

\documentclass{article}
\usepackage[margin = 1in]{geometry}
\usepackage{tikz}
\usetikzlibrary{%
    backgrounds,%
    decorations.pathmorphing,%
    calc,%
    shapes,%
    shapes.geometric,%
    patterns,%
}

\begin{document}

\newcommand\treedrawing[1]{%
    \tikzset{%
        treetop/.style = {decoration    = {random steps, segment length=0.4mm},decorate},%
        trunk/.style = {decoration={random steps, segment length=2mm, amplitude=0.2mm},decorate}%
    }
\begin{scope}[shift={(#1)}]
    \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{tikzpicture}
    \begin{pgfonlayer}{background}
        \shade[bottom color=cyan!60!black, top color=blue!20!white] (0,0) rectangle (10,10);
    \end{pgfonlayer}
    \treedrawing{2,5}
    \treedrawing{5,5}
    \treedrawing{8,5}
\end{tikzpicture}
\end{document}
jub0bs
  • 58,916