Aligning image and text in new command in TikZ

As a Teaching Assistant for a class, I am trying to draw a seating chart for the professor. The seating chart will have a photo of each student, the student's name, and where the student is sitting in the lecture room.

Using labels and anchors in TikZ, I am able to manually create a label for each student, and use that label to anchor the name of the student with the image of the student.

\documentclass[12pt]{article}

\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

\begin{document}

\begin{center}
\begin{tikzpicture}
\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);

\node[anchor=base,inner sep=0] (image1) at (4,4)
{\includegraphics[width=25mm]{empty-face.png}};
\node[text width=30mm,align=center,anchor=north] at (image1.south)
{George Washington};

\node[anchor=base,inner sep=0] (image2) at (8,4)
{\includegraphics[width=25mm]{empty-face.png}};
\node[text width=30mm,align=center,anchor=north] at (image2.south)

\node[anchor=base,inner sep=0] (image3) at (12,4)
{\includegraphics[width=25mm]{empty-face.png}};
\node[text width=30mm,align=center,anchor=north] at (image3.south)
{Thomas Jefferson};

\end{tikzpicture}
\end{center}

\end{document}


However, since there are 70 students in the class, it seems to be more elegant to define a new command \student to position the face and name of the student. More concretely, I want the following code to work.

\documentclass[12pt]{article}

\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

% Usage: \student{x coord}{y coord}{name}{picture file}
\newcommand{\student}[4]{
% What should I put in here????
}

\begin{document}

\begin{center}
\begin{tikzpicture}
\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);

\student{4}{4}{George Washington}{empty-face.png};
\student{12}{4}{Thomas Jefferson}{empty-face.png};
\end{tikzpicture}
\end{center}

\end{document}


My question is: How should I define the \student command? Because I need it to generate a new label each time in order to align the name and picture of each student.

One possible workaround is to let the \student command take 5 arguments, where I manually specify a new label each time. But this seems to be a clumsy and potentially error-inducing approach.

-
As you place the pictures in a matrix-like pattern, you might be interested in Using execute at begin node with \phantom and \pgfuseimage in TikZ? and you wouldn’t have to manually specify x and y coordinates; just place the pictures/names in a matrix. –  Qrrbrbirlbel Feb 17 '13 at 0:39

You can get away with no node name at all with the label option. The label option is explained in the PGF manual in section 16.10 “The Label and Pin Options”, pp. 194ff.

If you want generic node names like image1, image2, image3 … you can use a counter:

\newcounter{qrr@imagecounter}
\newcommand{\student}[4]{% Usage: \student{x coord}{y coord}{name}{picture file}
\stepcounter{qrr@imagecounter}%
\node[anchor=base,inner sep=0,label={[text width=30mm,align=center]below:#3}]
(image\the\value{qrr@imagecounter})at (#1,#2) {\includegraphics[width=25mm]{#4}};%
}


Notes

• Remove the line \usepackage[demo]{graphicx} to include your actual pictures, it is only used for this MWE.
• I noticed the line

\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);


in your code which does nothing except drawing a white rectangle (the border is white, the area is not colored in any way).

I guess you actually want to make the TikZ picture bigger so that the the coordinate (0,0) lies mat the lower left corner of the page.

Let me propose two separate enhancements:

1. Instead of the lengthy path use the rectangle operation

(0,0) rectangle (43.1,27.9)


and instead of a white drawing use this rectangle as the bounding box (this is what you actually do here: you extend the bounding box so that TeX sees a bigger TikZ picture box and places it accordingly):

\useasboundingbox (0,0) rectangle (43.1,27.9);


\useasboundingbox is a short-cut to \path[use as bounding box], meaning you could still use the rectangle to draw/fill something with \draw[use as bounding box, green].

Note also that you can use all of TeX length units in TikZ as well, you could even use

\useasboundingbox (0,0) rectangle (17in,11in);


and all is well? Not really because we now have a warning of TeX about an overfull \hbox. This comes from the paragraph indention that is inserted automatically in front of the TikZ picture box. Add \noindent in front of \begin{tikzpicture}.

(I suspect that this is also the reason you have not used the full (43.18,27.94) in your example? Also the line width (default 0.4 pt) of your white rectangle added an additional spacing resulting in even worse output and complicated everything even more (see the path specifier clip and the options trim left and trim right).

2. You want to have (0,0) at the lower left corner of the page? Then move it there!

With the special node current page and the options overlay and remember picture we can do

\begin{tikzpicture}[overlay,remember picture,shift=(current page.south west)]


which does the same without \noindent and a page-sized bounding box. (You can/should comment out the \noindent and \useasboundingbox lines in that case.)

The overlay/remember picture solution needs two LaTeX compilations (it uses the .aux file).

\fill (0,0) circle (5pt);


to check where the coordinate (0,0) lies.

Code

\documentclass[12pt]{article}
\usepackage[demo]{graphicx}
\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

% Usage: \student{x coord}{y coord}{name}{picture file}
\newcommand{\student}[4]{%
\node[anchor=base,inner sep=0] (x) at (#1,#2)
{\includegraphics[width=25mm]{#4}} node[text width=30mm,align=center,anchor=north] at(\tikzlastnode.south) {#3};%
}

\begin{document}
\noindent
\begin{tikzpicture}%[overlay,remember picture,shift=(current page.south west)]
\useasboundingbox (0,0) rectangle (17in,11in);

\student{4}{4}{George Washington}{empty-face.png};
\student{12}{4}{Thomas Jefferson}{empty-face.png};
\end{tikzpicture}
\end{document}


Output

-
Thank you for your answer! I didn't know that there existed a label option so this is very helpful. –  I Like to Code Feb 17 '13 at 2:02
@ILiketoCode You are welcome. Please see my updated answer regarding your \draw[white] call. –  Qrrbrbirlbel Feb 17 '13 at 2:56

You can use:

% Usage: \student{x coord}{y coord}{name}{picture file}{image label}
\newcommand{\student}[5]{%
\node[anchor=base,inner sep=0] (image#5) at (#1,#2)
{\includegraphics[width=25mm]{#4}};
\node[text width=30mm,align=center,anchor=north] at (image#5.south)
{#3};
}%


Code:

\documentclass[12pt]{article}

\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

% Usage: \student{x coord}{y coord}{name}{picture file}{image label}
\newcommand{\student}[5]{%
\node[anchor=base,inner sep=0] (image#5) at (#1,#2)
{\includegraphics[width=25mm]{#4}};
\node[text width=30mm,align=center,anchor=north] at (image#5.south)
{#3};
}%

\begin{document}

\begin{center}
\begin{tikzpicture}
\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);

\student{4}{4}{George Washington}{example-image-a}{1};
\student{12}{4}{Thomas Jefferson}{example-image}{3};
\end{tikzpicture}
\end{center}

\end{document}


-

Basic Version:

To answer you initial question, simply use #<n> when you need the nth parameter to the macro.

Notes:

• Since you do not appear to be using the name of the node after you place the image and the label, I just names the nodes as X.

Further Improvements:

• Using a \foreach loop you can automate this further and not have to provide the coordinates, and instead just provide two parameters: the name, and the name of the image. If you are ok with naming the file of the image based on the name of the student then you could have only one option: the students name. But since names can contain characters that many not be useable as file names, I'd actually make the image file name an optional parameter.

Code:

\documentclass[12pt]{article}
\usepackage[demo]{graphicx}
\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

% Usage: \student{x coord}{y coord}{name}{picture file}
\newcommand{\student}[4]{%
% What should I put in here????
\node[anchor=base,inner sep=0] (X) at (#1,#2)
{\includegraphics[width=25mm]{#4}};
\node[text width=30mm,align=center,anchor=north] at (X.south)
{#3};
}

\begin{document}

\begin{center}
\begin{tikzpicture}
\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);

\student{4}{4}{George Washington}{empty-face.png};
\student{12}{4}{Thomas Jefferson}{empty-face.png};
\end{tikzpicture}
\end{center}

\end{document}


Enhanced Version:

Besides creating a separate command, you can also use a \foreach loop to simplify things. So, in the example below, if you have 3 rows of students you specify them as:

\newcommand*{\ListOfStudents}{%
{George Washington, John Adams, Thomas Jefferson},%
{Albert Einstien, Steven Hawings, Kip Thorpe},%
{Steve Jobs, Gil Amelio, John Scully}%
}%


Each brace group defines a row from the front to the back.

Code:

\documentclass[12pt]{article}
\usepackage[demo]{graphicx}
\usepackage[margin=0in,paperwidth=17in, paperheight=11in]{geometry}
\usepackage{tikz}

% Usage: \student{x coord}{y coord}{name}{picture file}
\newcommand{\student}[4]{%
% What should I put in here????
\node[anchor=base,inner sep=0] (X) at (#1,#2)
{\includegraphics[width=25mm]{#4}};
\node[text width=30mm,align=center,anchor=north] at (X.south)
{#3};
}

\newcommand*{\ListOfStudents}{%
{George Washington, John Adams, Thomas Jefferson},%
{Albert Einstien, Steven Hawings, Kip Thorpe},%
{Steve Jobs, Gil Amelio, John Scully}%
}%

\begin{document}

\begin{center}
\begin{tikzpicture}
\draw[white] (0,0) -- (43.1,0) -- (43.1,27.9) -- (0,27.9) -- (0,0);

\foreach [count=\Row] \RowOfStudents in \ListOfStudents {%
\foreach [count=\Col] \StudentName/\Image in \RowOfStudents {%
\student{4*\Col}{5*\Row}{\StudentName}{\Image}
}
}%
\end{tikzpicture}
\end{center}

\end{document}

-