# what is the simplest possible way to make a tikz shape with ports?

I want to create diagrams with shapes connected by lines like circuittikz, but the online instructions and examples confuse me. Here is a MWE:

\documentclass[12pt]{article}

\usepackage{etoolbox}
\usepackage{pgfplots}
\usepackage{tikz}

% specify tikz libraries needed
\usetikzlibrary{
arrows.meta,automata,backgrounds,calc,chains,decorations,intersections,
% need 1.15 compatibility
\pgfplotsset{
compat=1.15,
legend style = {font = \LARGE},
}

\newcommand\CM[2]{
\begin{scope}[shift={#2}]
\draw (0,-0.866) -- (0,-2);
\fill (-1,-0.866) -- (+1,-0.866) -- (0,+0.866) -- cycle;
\draw (-1,+1) -- (0,0) -- (+1,+1);
\draw (-2,-0.433) -- (+2,-0.433);
\fill(0,-2) circle (0.1);       % O
\fill(-2,-0.433) circle (0.1);  % L
\fill(+2,-0.433) circle (0.1);  % R
\fill(-1,+1) circle (0.1);      % I
\fill(+1,+1) circle (0.1);      % J
\end{scope}
}

\listfiles
\begin{document}

\begin{tikzpicture}
\CM{A}{(-3,-3)}                        % example shape with terminals
\CM{B}{(+3,+3)}                        % example shape with terminals
%\node[CM](A) at (-3,-3);              % preferred syntax
%\node[CM](B) at (+3,+3);              % preferred syntax

\draw (-1,-3-0.433) -- (+1,+3-0.433);  % example connecting line
%\draw (A.J) -- (B.I);                 % preferred syntax
\end{tikzpicture}

\end{document}


I want to label all the circles as ports such as O, L, R, I, J such that if I instance the shape twice with node names A and B, I can then connect them by a line as in \draw (A.J) -- (B.I); which would connect the named circles with lines.

I would be happy to do this with custom tikzset or pgfdeclareshape, but nothing I find online seems to fit what I want to do with simplicity and clarity.

This can be done with a pic. Just use (A-J) instead of (A.J) to refer to your custom “anchors,” because if you use e.g. A.J, TikZ will look for a shape named A and won't find it.

Note: you should use circle[radius=〈length〉] rather than the obsolete syntax circle (〈length〉) which can cause problems (see here and here for instance). Since all circles in your pic have the same radius, I've factored it out using every circle/.style={radius=0.1}.

\documentclass[tikz, border=1mm]{standalone}

\tikzset{
stuff/.pic={
\draw (0,-0.866) -- (0,-2);
\fill (-1,-0.866) -- (+1,-0.866) -- (0,+0.866) -- cycle;
\draw (-1,+1) -- (0,0) -- (+1,+1);
\draw (-2,-0.433) -- (+2,-0.433);
\fill (0,-2) coordinate (-O) circle;       % O
\fill (-2,-0.433) coordinate (-L) circle;  % L
\fill (+2,-0.433) coordinate (-R) circle;  % R
\fill (-1,+1) coordinate (-I) circle;      % I
\fill (+1,+1) coordinate (-J) circle;      % J
\end{scope}
}
}

\begin{document}

\begin{tikzpicture}
\pic[draw=blue, fill=blue] (A) at (-3,-3) {stuff};
\pic (B) at (3,3) {stuff};

\draw[red] (A-J) -- (B-I);
\end{tikzpicture}

\end{document}


• This is exactly what I wanted. Thank you. – jlettvin Apr 11 at 19:00
• Glad to hear that. By the way, better use the syntax circle[radius=length] as the older syntax sometimes leads to weird problems. I'll update this in the answer when I'm back at my computer. – frougon Apr 11 at 19:12
• This is done now, using every circle/.style={radius=0.1} for nice factoring. – frougon Apr 11 at 23:05
• I tried the circle[radius=length] and it broke my compile. I will try putting this new recommendation in my tikzset. – jlettvin Apr 12 at 18:59
• My error. I used the literal word "length". The second form worked just fine. Thanks. – jlettvin Apr 13 at 4:35

I would place the code of your element into a pic environment and make the coordinates of the ports accessible to the outside via coordinate definitions.

\documentclass[10pt]{article}
\usepackage{tikz}
\usepackage[rotatelabels]{circuitikz}
\begin{document}
\begin{tikzpicture}[
new element/.pic = {
\begin{scope}[shift={(2, 0.433)}]
\coordinate (-center)   at (0,0);
\draw       (0,-0.866)  -- (0,-2);
\fill       (-1,-0.866) -- (+1,-0.866) -- (0,+0.866) -- cycle;
\draw       (-1,+1)     -- (0,0)       -- (+1,+1);
\draw       (-2,-0.433) -- (+2,-0.433);
\fill       (0,-2)      coordinate(-O);
\fill       (-2,-0.433) coordinate(-L);
\fill       (+2,-0.433) coordinate(-R);
\fill       (-1,+1)     coordinate(-I);
\fill       (+1,+1)     coordinate(-J);
\end{scope}
}
]
\draw (0,0) to[R=$R$, *-*] (2,0) pic (X) {new element} (X-R) to[R=$R$, *-*] ++(2,0);

\foreach \i in {O,I,J} {
\draw (X-\i) to[R=$R$, *-*] ($(\tikztostart)!-2cm!(X-center)$);
}

\end{tikzpicture}
\end{document}

• This is excellent. I learned what I needed from frougon, but you added some unexpected improvements. Thank you. – jlettvin Apr 11 at 19:02