3

I want to generate TikZ \pics dynamically. All information I need to setup the pic (name, x-coord, y-coord) are given in a tabular.

Is there a way to inject these information to the TikZ environment and draw them? Otherwise I always have to synchronize the graphical information in TikZ and the text information in my tabular environment.

I'm also open to define these information in a complete other format and then inject it to the tabular AND TikZ environment. I just want to keep a single source of truth.

\documentclass{article}%
\usepackage[a3paper,left=10mm,right=10mm,top=10mm,bottom=10mm]{geometry}%
\usepackage{courier}%
\usepackage[T1]{fontenc}%
\usepackage[parfill]{parskip}%
\usepackage[utf8]{inputenc}%
\usepackage{caption}%
\usepackage{graphicx}%
\usepackage{tikz}%
\tikzset{
PowerSupply/.pic={
\node{\includegraphics[scale=0.05,angle=270]{powerSupply.png}};},
}

\begin{document}
\section*{Electrical Installation Plan}
\subsection*{Component List}

\begin{center}
\begin{tabular}{|c|c|c|c|}
\hline
\textbf{ID} & \textbf{Description} & \textbf{X-Pos} & \textbf{Y-Pos} \\ \hline
A1F5F & PowerSupply1 & 3400 & 2000 \\ \hline %Input 1
7ZF3I & PowerSupply2 & 3400 & 2500 \\ \hline %Input 2
\hline
\end{tabular}
\end{center}

\pagenumbering{gobble}
\begin{figure}[h!]
\centering
\scalebox{2.0}{
\begin{tikzpicture}[x=0.01mm, y=-0.01mm]
\node[inner sep=0pt] (ground_floor) {\includegraphics[width=99.0mm,height=107.4mm]{groundFloor.png}};
\tikzset{shift=(ground_floor.north west)}

\draw[blue, ->, line width=1pt] (0,0) -- (10000,0);
\draw[blue, line width=1pt] (10000,0) --node[scale=0.5,black,above=1mm,align=center]{[mm]}(10000,0);
\foreach \x in {0,1000,...,9000} \draw[blue, line width=1pt] (\x,-100) --node[scale=0.5,black,above=1mm,align=center]{\x} (\x,100);

\draw[blue, ->, line width=1pt] (0,0) -- (0,11000);
\draw[blue, line width=1pt] (0,11000) --node[scale=0.5,black,left=1mm,align=center]{[mm]}(0,11000);
\foreach \y in {0,1000,...,10000} \draw[blue, line width=1pt] (-100,\y) --node[scale=0.5,black,left=1mm,align=center]{\y} (100,\y);

\pic at (3450,2000) {PowerSupply}; %This must be generated automatically from line 2 (ID: A1F5F)
\pic at (3450,2500) {PowerSupply}; %This must be generated automatically from line 3 (ID: 7ZF3I)
\end{tikzpicture}}
\caption{Ground Floor}
\end{figure}
\vfill
\clearpage
\end{document}

Example

EXAMPLE IMAGES

powerSupply groundFloor

2 Answers 2

2

You can make use of the pgfplotstable package (which loads pgfplots and tikz in the background) and read in a CSV file which you can then process and use to place \pics or whatever you want to do. I'd probably add a column for the rotation, so you can place the \pic at other places as well.

For the following MWE, I also included parts of my answer to your other question:

\documentclass{article}
\usepackage[a4paper, margin=10mm]{geometry}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}

\begin{filecontents}{data.csv}
id, name, x-coord, y-coord, rotation
A1F5F, PowerSupply1, 3590, 2000, 270 
7ZF3I, PowerSupply2, 3590, 2500, 270
O7PYQ, PowerSupply3, 4250, 6070, 180
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}{\csvdata}
\pgfplotstablegetrowsof{\csvdata}
\pgfmathtruncatemacro\CSVDataRows{\pgfplotsretval-1} 

\tikzset{
    PowerSupply/.pic={
        \node[anchor=north, inner sep=0pt]
            {\includegraphics[scale=0.09]{powerSupply}};
    },
}

\begin{document}
\pagenumbering{gobble}

\section*{Electrical Installation Plan}
\subsection*{Component List}

\begin{center}
\pgfplotstabletypeset[
    col sep=comma,
    columns={id, name, x-coord, y-coord},
    columns/id/.style={
        column name=ID,
        string type
    },
    columns/name/.style={
        column name=Description,
        string type
    },
    columns/x-coord/.style={
        column name=X-Pos
    },
    columns/y-coord/.style={
        column name=Y-Pos,
        column type/.add={}{|}
    },
    column type/.add={|}{},
    after row={\hline},
    every head row/.style={before row=\hline},
]{data.csv}
\end{center}

\begin{figure}[h!]
\centering
\begin{tikzpicture}[x=0.01mm, y=-0.01mm]
    \node[inner sep=0pt] (ground_floor)   
        {\includegraphics[width=99.0mm, height=107.4mm]{groundFloor}};
    
    \begin{scope}[shift=(ground_floor.north west)]
        \draw[blue, ->, line width=1pt] (0,0) -- (10000,0);
        \draw[blue, ->, line width=1pt] (0,0) -- (0,11000);
        
        \foreach \x in {0,1000,...,9000} {
            \draw[blue, line width=1pt] (\x,-100) -- 
                node[black, above=1mm] {\tiny\x mm} (\x,100);
        }
        \foreach \y in {0,1000,...,10000} {
            \draw[blue, line width=1pt] (-100,\y) --
                node[black, left=1mm]{\tiny\y mm} (100,\y);
        }

        \foreach \row in {0,...,\CSVDataRows} {
            \pgfplotstablegetelem{\row}{x-coord}\of{\csvdata}
            \pgfmathsetmacro{\x}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{y-coord}\of{\csvdata}
            \pgfmathsetmacro{\y}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{rotation}\of{\csvdata}
            \pgfmathsetmacro{\r}{\pgfplotsretval}
            \pic[rotate=\r, transform shape] at (\x,\y) {PowerSupply};
        }
    \end{scope}
\end{tikzpicture}
\caption{Ground Floor}
\end{figure}
\vfill
\clearpage
\end{document}

enter image description here


Extension to add a label to the node. Since you want to use a node to include the image, you need to add transform shape to the \pic which, however, would also rotate a label attached to the node. If you want the label not to be rotated, you need to un-rotate it.

I extended the \pic code so that the \pic can now take arguments. These can be used to add a label and position this label to the parent node.

\documentclass{article}
\usepackage[a4paper, margin=10mm]{geometry}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}

\begin{filecontents}{data.csv}
id, name, x-coord, y-coord, rotation
A1F5F, PowerSupply1, 3590, 2000, 270 
7ZF3I, PowerSupply2, 3590, 2500, 270
O7PYQ, PowerSupply3, 4250, 6070, 180
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}{\csvdata}
\pgfplotstablegetrowsof{\csvdata}
\pgfmathtruncatemacro\CSVDataRows{\pgfplotsretval-1} 

\tikzset{
    pics/PowerSupply/.style={
        code={
            \tikzset{PowerSupply/.cd, #1}
            \node[anchor=north, inner sep=0pt] (-p)
                {\includegraphics[scale=0.09]{powerSupply}};
            \node[
                inner sep=0pt,
                anchor={90+\pgfkeysvalueof{/tikz/PowerSupply/label position}},
                rotate={-1*\pgfkeysvalueof{/tikz/PowerSupply/label position}}
            ] at (-p.south) {\tiny \pgfkeysvalueof{/tikz/PowerSupply/label}};
        }
    },
    PowerSupply/label/.initial={},
    PowerSupply/label position/.initial={0}
}

\begin{document}
\pagenumbering{gobble}

\section*{Electrical Installation Plan}
\subsection*{Component List}

\begin{center}
\pgfplotstabletypeset[
    col sep=comma,
    columns={id, name, x-coord, y-coord},
    columns/id/.style={
        column name=ID,
        string type
    },
    columns/name/.style={
        column name=Description,
        string type
    },
    columns/x-coord/.style={
        column name=X-Pos
    },
    columns/y-coord/.style={
        column name=Y-Pos,
        column type/.add={}{|}
    },
    column type/.add={|}{},
    after row={\hline},
    every head row/.style={before row=\hline},
]{data.csv}
\end{center}

\begin{figure}[h!]
\centering
\begin{tikzpicture}[x=0.01mm, y=-0.01mm]
    \node[inner sep=0pt] (ground_floor)   
        {\includegraphics[width=99.0mm, height=107.4mm]{groundFloor}};
    
    \begin{scope}[shift=(ground_floor.north west)]
        \draw[blue, ->, line width=1pt] (0,0) -- (10000,0);
        \draw[blue, ->, line width=1pt] (0,0) -- (0,11000);
        
        \foreach \x in {0,1000,...,9000} {
            \draw[blue, line width=1pt] (\x,-100) -- 
                node[black, above=1mm] {\tiny\x mm} (\x,100);
        }
        \foreach \y in {0,1000,...,10000} {
            \draw[blue, line width=1pt] (-100,\y) --
                node[black, left=1mm]{\tiny\y mm} (100,\y);
        }

        \foreach \row in {0,...,\CSVDataRows} {
            \pgfplotstablegetelem{\row}{x-coord}\of{\csvdata}
            \pgfmathsetmacro{\x}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{y-coord}\of{\csvdata}
            \pgfmathsetmacro{\y}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{rotation}\of{\csvdata}
            \pgfmathsetmacro{\r}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{id}\of{\csvdata}
            \pgfmathsetmacro{\i}{"\pgfplotsretval"}
            \pic[rotate=\r, transform shape] at (\x,\y) {
                PowerSupply={
                    label={\i},
                    label position={\r}
                }
            };
        }
    \end{scope}
\end{tikzpicture}
\caption{Ground Floor}
\end{figure}
\vfill
\clearpage
\end{document}

enter image description here


You can also rename the \pic to, say, ElectricComponent and add another column to your list for the type of the component. Then you can use the same \pic to place different pictures:

\documentclass{article}
\usepackage[a4paper, margin=10mm]{geometry}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}

\begin{filecontents}{data.csv}
id, name, type, x-coord, y-coord, rotation
A1F5F, PowerSupply1, PowerSupply, 3590, 2000, 270 
7ZF3I, PowerSupply2, PowerSupply, 3590, 2500, 270
O7PYQ, PowerSupply3, PowerSupply, 4250, 6070, 180
A7HAZ, Switch1, singleSwitch, 5700, 6070, 180
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}{\csvdata}
\pgfplotstablegetrowsof{\csvdata}
\pgfmathtruncatemacro\CSVDataRows{\pgfplotsretval-1} 

\tikzset{
    pics/ElectricComponent/.style={
        code={
            \tikzset{ElectricComponent/.cd, #1}
            \node[anchor=north, inner sep=0pt] (-p)
                {\includegraphics[scale=0.09]{\pgfkeysvalueof{/tikz/ElectricComponent/type}}};
            \node[
                inner sep=0pt,
                anchor={90+\pgfkeysvalueof{/tikz/ElectricComponent/label position}},
                rotate={-1*\pgfkeysvalueof{/tikz/ElectricComponent/label position}}
            ] at (-p.south) {\tiny \pgfkeysvalueof{/tikz/ElectricComponent/label}};
        }
    },
    ElectricComponent/type/.initial={PowerSupply},
    ElectricComponent/label/.initial={},
    ElectricComponent/label position/.initial={0}
}

\begin{document}
\pagenumbering{gobble}

\section*{Electrical Installation Plan}
\subsection*{Component List}

\begin{center}
\pgfplotstabletypeset[
    col sep=comma,
    columns={id, name, x-coord, y-coord},
    columns/id/.style={
        column name=ID,
        string type
    },
    columns/name/.style={
        column name=Description,
        string type
    },
    columns/x-coord/.style={
        column name=X-Pos
    },
    columns/y-coord/.style={
        column name=Y-Pos,
        column type/.add={}{|}
    },
    column type/.add={|}{},
    after row={\hline},
    every head row/.style={before row=\hline},
]{data.csv}
\end{center}

\begin{figure}[h!]
\centering
\begin{tikzpicture}[x=0.01mm, y=-0.01mm]
    \node[inner sep=0pt] (ground_floor)   
        {\includegraphics[width=99.0mm, height=107.4mm]{groundFloor}};
    
    \begin{scope}[shift=(ground_floor.north west)]
        \draw[blue, ->, line width=1pt] (0,0) -- (10000,0);
        \draw[blue, ->, line width=1pt] (0,0) -- (0,11000);
        
        \foreach \x in {0,1000,...,9000} {
            \draw[blue, line width=1pt] (\x,-100) -- 
                node[black, above=1mm] {\tiny\x mm} (\x,100);
        }
        \foreach \y in {0,1000,...,10000} {
            \draw[blue, line width=1pt] (-100,\y) --
                node[black, left=1mm]{\tiny\y mm} (100,\y);
        }

        \foreach \row in {0,...,\CSVDataRows} {
            \pgfplotstablegetelem{\row}{x-coord}\of{\csvdata}
            \pgfmathsetmacro{\x}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{y-coord}\of{\csvdata}
            \pgfmathsetmacro{\y}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{rotation}\of{\csvdata}
            \pgfmathsetmacro{\r}{\pgfplotsretval}
            \pgfplotstablegetelem{\row}{type}\of{\csvdata}
            \pgfmathsetmacro{\t}{"\pgfplotsretval"}
            \pgfplotstablegetelem{\row}{id}\of{\csvdata}
            \pgfmathsetmacro{\i}{"\pgfplotsretval"}
            \pic[rotate=\r, transform shape] at (\x,\y) {
                ElectricComponent={
                    type={\t},
                    label={\i},
                    label position={\r}
                }
            };
        }
    \end{scope}
\end{tikzpicture}
\caption{Ground Floor}
\end{figure}
\vfill
\clearpage
\end{document}

enter image description here


Adding the icons to the table can be achieved without any TikZ magic:

\documentclass{article}
\usepackage[a4paper, margin=10mm]{geometry}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}

\begin{filecontents}{data.csv}
id, name, type, x-coord, y-coord, rotation
A1F5F, PowerSupply1, powerSupply, 3590, 2000, 270 
7ZF3I, PowerSupply2, powerSupply, 3590, 2500, 270
O7PYQ, PowerSupply3, powerSupply, 4250, 6070, 180
A7HAZ, Switch1, singleSwitch, 5700, 6070, 180
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}{\csvdata}

\begin{document}
\pagenumbering{gobble}

\begin{center}
\pgfplotstabletypeset[
    col sep=comma,
    columns={id, name, type, x-coord, y-coord},
    columns/id/.style={
        column name=ID,
        string type
    },
    columns/name/.style={
        column name=Description,
        string type
    },
    columns/type/.style={
        column name=Type,
        assign cell content/.code={
            \pgfkeyssetvalue{/pgfplots/table/@cell content}{
                \includegraphics[scale=0.09]{##1}
            }
        }
    },
    columns/x-coord/.style={
        column name=X-Pos
    },
    columns/y-coord/.style={
        column name=Y-Pos,
        column type/.add={}{|}
    },
    column type/.add={|}{},
    after row={\hline},
    every head row/.style={before row=\hline},
]{data.csv}
\end{center}

\end{document}

enter image description here

22
  • 1
    @PascalS I added a link to the pgfplotstable package at CTAN where you can also find its documentation. The package has a lot of functionality. You may want to style the table differently or format the numbers in another way. Feb 17 at 20:14
  • 1
    @PascalS I added a variant to the original code. Feb 17 at 22:55
  • 1
    Got it! {\includegraphics[scale=0.09]{../Images/ElectricComponents/\pgfkeysvalueof{/tikz/ElectricComponent/type}}}; I didn't recognize that the images are stored in a sub folder. Thank you so much, I really appreciate!
    – PascalS
    Feb 18 at 9:04
  • 1
    @PascalS I try to be better than ChatGPT =P Feb 22 at 21:54
  • 1
    @PascalS You can remove (or at least change) rotate={-1*\pgfkeysvalueof{/tikz/ElectricComponent/label position}. Currently it reverts the rotation of the image. If you delete it, the text will rotate together with the image. Feb 23 at 15:17
4

If we are using OpTeX, we don't need to use TikZ, because there is \puttext macro. The powerSupply.png image is saved to the \pwbox and this box is copied (and rotated) in the \fornum loop.

\newcount\pwtotal
\def\d #1, #2, #3, #4, #5 {\advance\pwtotal by1
   \sxdef{\pws:id}{#1}\sxdef{\pws:d}{#2}\sxdef{\pws:x}{#3}\sxdef{\pws:y}{#4}\sxdef{\pws:r}{#5}%
}
\def\pws{pws:\the\pwtotal}

\def\putpw#1{\pdfsave\pdfrotate{#1}\copy\pwbox\pdfrestore}
\newdimen\pwunit \pwunit=.01mm

%% Save power supply image:

\newbox\pwbox
\setbox\pwbox=\hbox to0pt{\hss \picw=5mm \vbox to0pt{\inspic{powerSupply.png}\vss}\hss}

%% Save data:

\d A1F5F, PowerSupply1, 3590, 2000, 270 
\d 7ZF3I, PowerSupply2, 3590, 2500, 270
\d O7PYQ, PowerSupply3, 4250, 6070, 180

%% Print table:

\noindent\hfil\table{|c|c|c|c|}{\crl
   \bf Id & \bf Description & \bf X-Pos & \bf Y-pos \crl
   \fornum 1..\pwtotal \do{\cs{pws:#1:id}&\cs{pws:#1:d}&\cs{pws:#1:x}&\cs{pws:#1:y}\crl}
}
\bigskip

%% Draw final image:

\noindent\hfil\vbox{
   \picwidth=99mm \picheight=107.4mm
   \vbox to0pt{\inspic{groundFloor.png}\vss} % load background image
   \fornum 1..\pwtotal \do{
      \puttext \cs{pws:#1:x}\pwunit -\cs{pws:#1:y}\pwunit {\putpw{\cs{pws:#1:r}}}
   }
   \kern \picheight
}
\bye

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .