# Draw a node as a square with TikZ

I googled but cannot find a solution. Is that possible to draw a node with TikZ which will be a square and NOT a rectangle?

Minimum working example can be something like this:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\node at (0,0) [circle,draw] (c100) {$c_{100}$};
\node at (3,0) [rectangle,draw] (v100) {$v_{100}$};
\draw (c100) -- (v100);
\end{tikzpicture}
\end{document}


While circle is perfectly round, rectangle is just a rectangle:

And I want it to be a square. I did not find any shape like square or so.

-

This is surprisingly difficult. In the following code, I've defined a custom node shape square that inherits from the rectangle shape, but forces its size to be square. Unfortunately, the inheritance mechanism doesn't allow redefinition of inherited saved anchors, so I had to copy some code from the TikZ rectangle definition.

On the plus side, it should be correct in all cases (defining different values for inner [xy]sep, minimum {width,height} and outer [xy]sep) and has all the anchors of the rectangle shape.

\documentclass[tikz,margin=5pt]{standalone}
\usepackage{tikz}

\makeatletter
% the contents of \squarecorner were mostly stolen from pgfmoduleshapes.code.tex
\def\squarecorner#1{
% Calculate x
%
% First, is width < minimum width?
\pgf@x=\the\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<\pgf@xb%
% yes, too small. Enlarge...
\pgf@x=\pgf@xb%
\fi%
% Calculate y
%
% First, is height+depth < minimum height?
\pgf@y=\ht\pgfnodeparttextbox%
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}%
\pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<\pgf@yb%
% yes, too small. Enlarge...
\pgf@y=\pgf@yb%
\fi%
%
% this \ifdim is the actual part that makes the node dimensions square.
\ifdim\pgf@x<\pgf@y%
\pgf@x=\pgf@y%
\else
\pgf@y=\pgf@x%
\fi
%
% Now, calculate right border: .5\wd\pgfnodeparttextbox + .5 \pgf@x + #1outer sep
\pgf@x=#1.5\pgf@x%
\pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}%
% Now, calculate upper border: .5\ht-.5\dp + .5 \pgf@y + #1outer sep
\pgf@y=#1.5\pgf@y%
\pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}%
}
\makeatother

\pgfdeclareshape{square}{
\savedanchor\northeast{\squarecorner{}}
\savedanchor\southwest{\squarecorner{-}}

\foreach \x in {east,west} \foreach \y in {north,mid,base,south} {
\inheritanchor[from=rectangle]{\y\space\x}
}
\foreach \x in {east,west,north,mid,base,south,center,text} {
\inheritanchor[from=rectangle]{\x}
}
\inheritanchorborder[from=rectangle]
\inheritbackgroundpath[from=rectangle]
}

\begin{document}
\begin{tikzpicture}
\node[draw,square] {square with rectangular node text};
\end{tikzpicture}
\end{document}


-
This looks like the most precise solution. But of course, not the easiest one :) Well, once put in the doc it is then easy to use. Thanks! – Yauhen Yakimenka Mar 21 at 18:13

Use the regular polygon shape from the shapes.geometric library. As Alenanno mentions in a comment, you can define your own style to reduce the verbosity.

I don't know how the size of that is calculated, there is a lot of whitespace in it. Setting inner sep to a negative value can reduce the size, but the value has to be modified depending on the length of the node label.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\begin{document}
\begin{tikzpicture}[square/.style={regular polygon,regular polygon sides=4}]
\node at (0,0) [circle,draw] (c100) {$c_{100}$};
\node at (3,0) [square,draw] (v100) {$v_{100}$};
\node at (3,-5) [square,inner sep=-1.3em,draw] {a much longer node label};
\node at (3,-5) [circle,draw] {a much longer node label};
\draw (c100) -- (v100);
\end{tikzpicture}
\end{document}


-
That seems like a good solution. Except that I need to write such a long phrase each time -- regular polygon,regular polygon sides=4. Is there a way to define a shortcut? And also the square is bigger than a circle with the same label - is there a way to make it have smaller inside margins? – Yauhen Yakimenka Mar 21 at 12:31
@YauhenYakimenka Define a tikz style (using \tikzset) like mysquare/.style={regular polygon,regular polygon sides=4, inner sep=0}, then just add mysquare to the nodes you want to affect. For the size, inner sep=0 solves it. – Alenanno Mar 21 at 12:34
Perfect! I put style definition \tikzset{square/.style={regular polygon,regular polygon sides=4,inner sep=0}} in the beginning of the document as I am going to use it a lot. Inner separator of 0 seems to be okay for not too big shapes. Thanks guys! – Yauhen Yakimenka Mar 21 at 13:00
@YauhenYakimenka I'd also add another style like every node/.style={draw} so they are all drawn by default. If you want to have one that is not drawn, just add draw=none to the exception node. – Alenanno Mar 21 at 19:12

Use minimum size= which changes both height and width which you can change singularly as well. Also, keep in mind that rectangle is the default shape, so no need to specify it.

Writing \node at (3,0) [minimum size=1cm,draw] (v100) {$v_{100}$}; you should get

-
This might be good starting workaround. However, as far as I understand, I should manually find a size which fits the node's label. Because if, say, it is $v_{100000000}$ the node will become rectangular again. – Yauhen Yakimenka Mar 21 at 12:09

Another solution. It uses width function to define node's size. As the same parameter is used as node contents and size delimiter, node's name and position must be declared before options or inside options.

\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}%
[square/.style={%
draw,
minimum width=width("#1"),
minimum height=width("#1")+2*\pgfshapeinnerysep,
node contents={#1}}]

\node at (0,0) [circle,draw] (c100) {$c_{100}$};
\node at (3,0) (v100) [square={$v_{100}$}];
%or
%       \node (v100) at (3,0)[square={$v_{100}$}];
%or
%       \node at (3,0) [square={$v_{100}$}, name=v100];
%or
%       \node[square={$v_{100}$}, name=v100, at={(3,0)}];

\node at (2,-3) (B) [square=a much longer node text];
\draw (c100) -- (v100);
\draw (B.south west) -- ++(45:6cm);
\end{tikzpicture}
\end{document}


-
Very interesting solution (altough I wonder whether a future version of TikZ can just have the rectangle shape respect the aspect ratio related options). One corner case that doesn't work: \node[square=I]; – wrtlprnft Apr 14 at 10:09
@wrtlprnft Yes I must admit that this solution only works when text horizontal component is larger than vertical one. Which doesn't happens with I. – Ignasi Apr 14 at 11:06
How about /utils/exec={\pgfmathsetmacro\squaresize{max(width("#1") + 2 * \pgfshapeinnerxsep, height("#1") + depth("#1") + 2 * \pgfshapeinnerysep)}},minimum size=\squaresize? Unfortunately, directly passing the expression to minimum size didn't work, hence the macro definition. – wrtlprnft Apr 14 at 11:32