# Reusing circuit code with nodes in TikZ

I'm new to TikZ/PGF (a week or so in), and am loving it. I've had good success making figures so far, but have a question about best practices for including multiple copies of a sub-circuit in a single figure. And doing so in a way that allows simple connections to the input/output nodes of the sub-circuit.

As a very rudimentary example (please excuse the free-handed drawing) in which I have a drawing with two repeated sub-circuits (contained within a rectangle).

So in this example, I'd like to define the amplifier circuit once, and then place it twice in the picture and connect wires to its input and output nodes. Does this require me to develop a library, or can the sub-circuit be written into the .tex file directly and then reused?

I did see the post about using a \newsavebox here, but I'm not sure how I would access the nodes in the circuit using that approach.

Any help is greatly appreciated. Many thanks.

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}

\begin{document}
\begin{tikzpicture}[circuit ee IEC,circuit logic US,x=3cm,y=2cm,semithick,
set resistor graphic=var resistor IEC graphic]

% Box on the left (non circuit stuff)
\draw (0,0) rectangle (2,2);
\draw (1,1) rectangle (1.8,1.8);
\draw (0.3,0.2) rectangle (0.5,0.5);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Begin the sub-circuit to be replicated
\node[contact] (A) at (2.5,0) {};
\node[contact] [right=1.5cm of A] (B) {};
\node[contact] [above=1.5cm of B] (C) {};
\node[contact] [right=1.0cm of B] (D) {};
\node[contact] [right=1.5cm of D] (E) {};
\node[buffer gate] [right=0.1 of D] (amp) {};
% Problem #1:  there is whitespace between the amp output and the line to node E
\draw (A) to [resistor] (B) (B) to [capacitor] (D) (D) to (amp) (amp) to (E);
\draw (B) to [resistor] (C);
% Problem #2: had to tune 0.54 to get vertical line to node E.  (output of amp)
% Must be a better way ...
\draw (D) -- ++(0,0.5) to [capacitor] ++(right:0.54) to (E);
\tikzset{black box/.style={draw=black, rectangle}};
\node(preampbox) [black box, fit=(A) (C) (E) (amp), inner sep=0.4cm] {};
%%%%%%%%%%%%%%  end subcircuit  %%%%%%%%%%%%%%%%%%

\end{tikzpicture}
\end{document}


-
You may wan't to check this. Possible duplicate? –  masu Sep 29 '13 at 17:07
Yes, I had linked to that in my original question, but I'm not sure how to access nodes of the circuit from within the savebox. For example, how would I tell TikZ to draw a line that terminates on the input resistor of the sub-circuit? –  user37464 Sep 29 '13 at 18:11
Why would you use a savebox? Isn't a for loop eligible? –  masu Sep 29 '13 at 18:55
The link you (and I) posted suggests using a savebox... I could use a \foreach with two iterations (one for each amplifier block). Is that the best way to go in this situation? –  user37464 Sep 29 '13 at 20:12
I’d to the following: Use relative coordinates to create that sub-path (the whole sub-circuit thing) and save it in an insert path. Then the fit library can be used to draw the box around it. Could you add the the code for the sub-circuit as well as the whole picture? (I’m not so familiar with circuits and won’t look up all the shapes and things.) –  Qrrbrbirlbel Sep 29 '13 at 22:12

Drawing the node only produces the outer rectangle, but it is used to define all the internal coordinates and the contact anchor points. \drawMyamp does the internal circuitry. By tradition, the origin is aligned with all of the contact anchor points.

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}

\newcommand{\UseGlobalScale}
{\pgfgettransformentries{\xscale}{\@tempa}{\@tempa}{\yscale}{\@tempa}{\@tempa}}

\let\xscale=*
\let\yscale=*

% ***************************** myamp node *********************************
% contact anchor points: left, above, out
% internal anchor points: A, B, C, D, E, F, G

\pgfdeclareshape{myamp}{

\savedmacro{\resize}{   % restore global scale factor
\if*\xscale \relax \else \pgftransformxscale{\xscale} \fi
\if*\yscale \relax \else \pgftransformyscale{\yscale} \fi
}

\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text} % this is required to center text in the node (not used here)
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\anchor{left}{\pgfpoint{-2cm}{0cm}}
\anchor{above}{\pgfpoint{0cm}{2cm}}
\anchor{out}{\pgfpoint{3cm}{0cm}}

\anchor{A}{\pgfpoint{-1.5cm}{0cm}}
\anchor{B}{\pgfpointorigin}
\anchor{C}{\pgfpoint{0cm}{1.5cm}}
\anchor{D}{\pgfpoint{1cm}{0cm}}
\anchor{E}{\pgfpoint{2.5cm}{0cm}}
\anchor{F}{\pgfpoint{1cm}{1cm}}
\anchor{G}{\pgfpoint{2.5cm}{1cm}}

\foregroundpath{ % draw border
\pgfpathrectanglecorners{\pgfpoint{-1.75cm}{-1cm}}{\pgfpoint{2.75cm}{1.75cm}}
\pgfusepath{draw}}
}

%************************ draw myamp components ****************************
% component names = #1 R1, #1 R2, #1 C1, #1 C2 and #1 opamp

\newcommand{\drawMyamp}[2]{ % #1 = node name, #2 = rotation angle
\draw
node[contact] at(#1.A){}
node[contact] at(#1.B){}
node[contact] at(#1.C){}
node[contact] at(#1.D){}
node[contact] at(#1.E){}
node[resistor,rotate=#2](#1 R1) at($(#1.A)!.5!(#1.B)$){}
node[resistor,rotate={90+#2}](#1 R2) at($(#1.B)!.5!(#1.C)$){}
node[capacitor,rotate=#2](#1 C1) at($(#1.B)!.5!(#1.D)$){}
node[capacitor,rotate=#2](#1 C2) at($(#1.F)!.5!(#1.G)$){}
node[buffer gate,rotate=#2](#1 opamp) at($(#1.D)!.5!(#1.E)$){};
\draw[thin]
(#1.left) -- (#1.A) -- (#1 R1.west)
(#1 R1.east) -- (#1.B) -- (#1 R2.west)
(#1 R2.east) -- (#1.C) -- (#1.above)
(#1.B) -- (#1 C1.west)
(#1 C1.east) -- (#1.D) -- (#1 opamp.west)
(#1.D) -- (#1.F) -- (#1 C2.west)
(#1 C2.east) -- (#1.G) -- (#1.E) -- (#1 opamp.east)
(#1.E) -- (#1.out);
}

%*************************************************************************

\begin{document}

\begin{tikzpicture}[circuit ee IEC,circuit logic US,x=3cm,y=2cm,semithick,
set resistor graphic=var resistor IEC graphic]

\UseGlobalScale % save scale factor for myamp

% Box on the left (non circuit stuff)
\draw (0,0) rectangle (2,2);
\draw (1,1) rectangle (1.8,1.8);
\draw (0.3,0.2) rectangle (0.5,0.5);

\draw (3,0) node[myamp,thick,dashed](amp1){};
\drawMyamp{amp1}{0}

\draw (3.1,2) node[myamp,color=red,rotate=90](amp2){};
\drawMyamp{amp2}{90}

\draw (amp1 R1.south) node[below]{$100 K\Omega$};
\end{tikzpicture}

\end{document}


There are two ways to add labels to the components. You could add a lot of arguments to the macro, or you can put labels in nodes at the anchor points.

-
Thank you. This solution relies on circuitikz as well as TikZ. Presumably there's a way to do this in TikZ? –  user37464 Sep 30 '13 at 20:38
Using Circuitikz is like using a library of Tikz. You lose nothing and gain a lot of components. But yes, the node definition is pure Tikz except for the line width, and the macro can be written using pure Tikz (it just takes longer). –  John Kormylo Sep 30 '13 at 20:53
Unfortunately, rotating the structure does not rotate the opamp. The only quick fix I can think of is to create a bipole version of the buffer shape. –  John Kormylo Oct 1 '13 at 4:06
I converted the circuitikz to tikz and added a rotation angle to the macro. –  John Kormylo Oct 1 '13 at 12:12
Excellent, thanks. A minor typo: \end{circuitikz} should be \end{tikzpicture}. Also although the components in sub-circuit scale (with e.g. [scale=0.25] as an argument to \begin{tikzpicture}, the border does not, nor do the component spacings. –  user37464 Oct 1 '13 at 13:58

Well, you could just pack the all the \nodes and paths in a macro and re-use it.

With TikZ though, you can save entire paths (and you can do all that on one path) and re-use that later. The starting point for the contact (A) is the current coordinate on the path.

(D) edge[to path={-- ++ (up:.5) to[capacitor] ([shift=(up:.5)] E) -- (E)}] (E)


you can also do

(D) edge[to path={-- ++ (up:.5) coordinate (aux) to[capacitor] (aux -| E) -- (E)}] (E)


(The ultimate (E) after the edge option is ignored, by the way.)

## Code

\documentclass[tikz]{standalone}
\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}
\tikzset{
saveuse path/.code 2 args={%
\pgfkeysalso{#1/.estyle={/tikz/insert path={#2}}}%
\global\expandafter\let\csname pgfk@\pgfkeyscurrentpath/.@cmd\expandafter\endcsname % not optimal as it is now global through out the document
\csname pgfk@\pgfkeyscurrentpath/.@cmd\endcsname
\pgfkeysalso{#1}}}
\begin{document}
\begin{tikzpicture}[
circuit ee IEC,
circuit logic US,
x=3cm, y=2cm, semithick,
set resistor graphic=var resistor IEC graphic
]
\path (2.5,0)
[saveuse path={subcirc}{{
[nodes=contact, node distance=1.5cm]
node                 (A) {}
node[right=    of A] (B) {}
node[above=    of B] (C) {}
node[right=1cm of B] (D) {}
node[right=    of D] (E) {} }
(D)   edge[buffer gate={name=amp}] (E)
(A)   edge [resistor]  (B)
(B)   edge [capacitor] (D)
(B)   edge [resistor]  (C)
(D) edge[to path={-- ++ (up:.5) to[capacitor] ([shift=(up:.5)] E) -- (E)}] (E)
node[draw=black, rectangle, fit=(A)(C)(E)(amp.south west)] (box) {}}]
(A) [late options={alias=A'}]
(2.5,2) [subcirc]
(A) [late options={alias=A''}]
;

\draw (A') to[bend left=90] (A'');
\end{tikzpicture}
\end{document}


-