# How can I make TikZ nodes center on a particular symbol/operator?

Here is a small example document.

\documentclass[a4paper]{amsart}

\usepackage{tikz}

\newcommand{\dju}{\mathbin{\coprod}}
\DeclareMathOperator{\id}{id}

\begin{document}

\begin{tikzpicture}[x = 45mm, y = 30mm]
\node (gh)   at (0, 1) {$G \dju H$};
\node (fgh)  at (1, 1) {$f(G) \dju H$};
\node (ggh)  at (0, 0) {$G \dju g(H)$};
\node (fggh) at (1, 0) {$f(G) \dju g(H)$};
\begin{scope}[->]
\draw (gh.east) -- (fgh.west)
node [midway, above] {$f \dju \id_H$};
\draw (gh.south) -- (ggh.north)
node [midway, left] {$\id_G \dju g$};
\draw (gh.south east) -- (fggh.north west)
node [midway, above right] {$f \dju g$};
\draw (fgh.south) -- (fggh.north)
node [midway, right] {$\id_{f(G)} \dju g$};
\draw (ggh.east) -- (fggh.west)
node [midway, below] {$f \dju \id_{g(H)}$};
\end{scope}
\end{tikzpicture}

\end{document}


This is what the document looks like when I compile it:

This diagram looks fairly reasonable, but perhaps it would look nicer if the vertical and horizontal arrows were centered on the disjoint union symbol (\coprod). The diagonal arrow should probably remain as it is, pointing from the bottom-right corner of the right-hand summand of the domain to the top-left corner of the left-hand summand of the codomain. Here is the above picture after I messed around with it in mspaint, to show you what I mean:

How would you go about making TikZ draw the diagram like this? One way that occurs to me is to take each of the four nodes and make the \dju and the two summands into separate nodes, with each summand positioned relative to the \dju node. However, it is not obvious that the math-mode spacing of the different symbols can be mimicked if you do this.

Unrelated question: In two places in this diagram, the spacing on the right-hand side of the disjoint union symbol seems wrong. This appears to happen when the math operator \id is on the left-hand side and an ordinary letter is on the right. Why does this happen? It does not happen if you change the \mathbin in the preamble to \mathord, but this also makes all of the spacings bigger. The effect does disappear if the \mathbin is removed altogether. I confess I do not remember why I put it there in my main document.

• Is there any particular reason you're not using the tikz-cd package? It would not solve your problem here, but it would make the code a lot shorter, and I think Harish Kumar's solution would still apply. – Charles Staats Nov 23 '13 at 13:43

# Remarks

I didn't change Harish's solution. I just reimplemented it using tikz-cd to show the shortened code.

# Implementation

\documentclass[a4paper]{amsart}
\usepackage{tikz-cd}
\newcommand{\dju}{\mathbin{\coprod}}
\DeclareMathOperator{\id}{id}
\newcommand{\Ga}{\hphantom{f()}G}
\newcommand{\Ha}{H\hphantom{g()}}
\begin{document}

\begin{tikzcd}
\Ga  \dju \Ha \arrow{dr}{f \dju \id_{g(H)}} \arrow{d}{\id_G \dju g} \arrow{r}{f \dju \id_H} & f(G) \dju \Ha \arrow{d}{\id_{f(G)} \dju g} \\
\Ga  \dju g(H) \arrow{r}{f \dju \id_{g(H)}}                                                 & f(G) \dju g(H)
\end{tikzcd}

Increased \texttt{row sep} and \texttt{column sep}:

\begin{tikzcd}[row sep=huge, column sep=huge]
\Ga  \dju \Ha \arrow{dr}{f \dju \id_{g(H)}} \arrow{d}{\id_G \dju g} \arrow{r}{f \dju \id_H} & f(G) \dju \Ha \arrow{d}{\id_{f(G)} \dju g} \\
\Ga  \dju g(H) \arrow{r}{f \dju \id_{g(H)}}                                                 & f(G) \dju g(H)
\end{tikzcd}
\end{document}


# Output

Things can get ugly... We can use phantom power.

\documentclass[a4paper]{amsart}

\usepackage{tikz}

\newcommand{\dju}{\mathbin{\coprod}}
\DeclareMathOperator{\id}{id}
\newcommand{\Ga}{\hphantom{f()}G}
\newcommand{\Ha}{H\hphantom{g()}}
\begin{document}

\begin{tikzpicture}[x = 45mm, y = 30mm]
\node (gh)   at (0, 1) {$\Ga \dju \Ha$};
\node (fgh)  at (1, 1) {$f(G) \dju \Ha$};
\node (ggh)  at (0, 0) {$\Ga \dju g(H)$};
\node (fggh) at (1, 0) {$f(G) \dju g(H)$};
\begin{scope}[->]
\draw[shorten <= -3ex] (gh.east) -- (fgh.west)
node [midway, above] {$f \dju \id_H$};
\draw (gh.south) -- (ggh.north)
node [midway, left] {$\id_G \dju g$};
\draw (gh.335) -- (fggh.north west)
node [midway, above right] {$f \dju g$};
\draw (fgh.south) -- (fggh.north)
node [midway, right] {$\id_{f(G)} \dju g$};
\draw (ggh.east) -- (fggh.west)
node [midway, below] {$f \dju \id_{g(H)}$};
\end{scope}
\end{tikzpicture}

\end{document}


It was Harish's answer that led me to the line of thinking that took me to this answer. However, I am posting it as a separate answer because it's quite different in the end. Harish, your answer was very competent and gave good results, I just found myself asking whether there was a way to do it without fudging things (for example, where does shorten <= -3ex come from in your code? Trial and error?) We need to know precisely how much to shorten arrows by, and this calls for the use of boxes and lengths.

\documentclass[a4paper]{amsart}

\usepackage{tikz}

\newcommand{\dju}{\mathbin{\coprod}}
\DeclareMathOperator{\id}{id}

\newlength{\lenA}
\newlength{\lenB}
\newlength{\lenC}
\newlength{\lenD}
\newlength{\lenE}
\newsavebox{\saveboxA}
\newsavebox{\saveboxB}
\newsavebox{\saveboxC}
\newsavebox{\saveboxD}

\begin{document}

\begin{tikzpicture}[x = 55mm, y = 35mm]
\settowidth{\lenA}{$G$}
\settowidth{\lenB}{$H$}
\settowidth{\lenC}{$f(G)$}
\settowidth{\lenD}{$g(H)$}
\pgfmathsetlength{\lenE}{max(\lenC, \lenD)}
\savebox{\saveboxA}[\lenE][r]{$G$}
\savebox{\saveboxB}[\lenE][r]{$f(G)$}
\savebox{\saveboxC}[\lenE][l]{$H$}
\savebox{\saveboxD}[\lenE][l]{$g(H)$}
\pgfmathsetlength{\lenB}{\lenB - \lenE}
\pgfmathsetlength{\lenC}{\lenE - \lenC}
\pgfmathsetlength{\lenD}{\lenD - \lenE}
\node (gh)   at (0, 1) {$\usebox{\saveboxA} \dju \usebox{\saveboxC}$};
\node (fgh)  at (1, 1) {$\usebox{\saveboxB} \dju \usebox{\saveboxC}$};
\node (ggh)  at (0, 0) {$\usebox{\saveboxA} \dju \usebox{\saveboxD}$};
\node (fggh) at (1, 0) {$\usebox{\saveboxB} \dju \usebox{\saveboxD}$};
\path (gh.east)         -- ++(\lenB, 0) coordinate (mghfghstart);
\path (fgh.west)        -- ++(\lenC, 0) coordinate (mghfghend);
\path (gh.south east)   -- ++(\lenB, 0) coordinate (mghfgghstart);
\path (fggh.north west) -- ++(\lenC, 0) coordinate (mghfgghend);
\path (ggh.east)        -- ++(\lenD, 0) coordinate (mgghfgghstart);
\path (fggh.west)       -- ++(\lenC, 0) coordinate (mgghfgghend);
\begin{scope}[->, every node/.style = {midway}]
\draw (mghfghstart)   -- (mghfghend)   node [above]       {$f \dju \id_H$};
\draw (gh.south)      -- (ggh.north)   node [left]        {$\id_G \dju g$};
\draw (mghfgghstart)  -- (mghfgghend)  node [above right] {$f \dju g$};
\draw (fgh.south)     -- (fggh.north)  node [right]       {$\id_{f(G)} \dju g$};
\draw (mgghfgghstart) -- (mgghfgghend) node [below]       {$f \dju \id_{g(H)}$};
\end{scope}
\end{tikzpicture}

\end{document}


The mystery of the bad spacing around \mathbin{\coprod} remains, but is unrelated to the subject matter of this question. (I tried defining \dju to be \amalg, but that too had bad spacing in the same situations.) To those people suggesting tikz-cd, I would, but for my current document I do not have too many commutative diagrams to draw and I don't feel like I would benefit enormously from adopting a new way of doing things when plain TikZ has enough functionality to do what I want to do.

• Putting the \id in a group, as in ${\id_G} \dju g$, fixes the problem. – Hammerite Nov 23 '13 at 20:35

Just for fun with plain TeX's math mode only.

\def\dju{\mathbin{\coprod}}
\def\id{\mathop{\rm id}}
\def\Ga{\hphantom{f()}G}
\def\Ha{H\hphantom{g()}}
\def\rar#1{\buildrel {#1} \over {\hbox to 4em{\rightarrowfill}}}
\def\dar#1{\Bigg\downarrow\rlap{$\scriptstyle#1$}}
\def\drar#1{\searrow\raise1ex\rlap{$\scriptstyle#1$}}
\matrix{ \Ga\dju \Ha & \rar{f\dju\id_H} & f(G)\dju \Ha\cr \noalign{\vskip2ex} \dar{\id_G\dju g} & \drar{f\dju g} & \dar{\id_{f(G)}\dju g} \cr \noalign{\vskip1ex} \Ga\dju g(H) & \rar{f\dju\id_{g(H)}} & f(G)\dju g(H)\cr }
\bye