5

please consider the following mwe:

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{positioning,  
                shapes}

\begin{document}
    \begin{tikzpicture}[
node distance = 3mm and 9mm,
 block/.style = {rectangle, draw, minimum height=22mm},
 ellip/.style = {draw, ellipse, align=center},
                    ]
\node (n1) [block] {block};
\node (n2) [ellip, above right=of n1.east]  {longer text\\ in two lines};
\node (n3) [ellip, below right=of n1.east]  {short\\ text};
    \end{tikzpicture}
\end{document}

enter image description here

why the distance between ellipses and block are different? do i miss something in positioning of ellipses? it seems that the text in shapes are aligned instead of shapes ...

edit: after reading tikz & pgf manual again, i have impression, that ellipses is actually build from two shapes: one (of rectangle form) for text and one tight fit over for ellipses shape. it seems that distance defined by positioning library consider "inner" text shape. to see this, please change node distance = 3mm and 9mm, in above mwe to node distance = 1mm and 9mm. resuted image is than:

enter image description here

is this a bug?

Zarko
  • 296,517

3 Answers3

3

If you anchor them west the left borders of the ellipsis will be aligned:

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{positioning,  
                shapes}

\begin{document}
    \begin{tikzpicture}[
node distance = 3mm and 9mm,
 block/.style = {rectangle, draw, minimum height=22mm},
 ellip/.style = {draw, ellipse, align=center},
                    ]
\node (n1) [block] {block};
\node (n2) [ellip, below right=of n1.north east,anchor=west]  {longer text\\ in two lines};
\node (n3) [ellip, above right=of n1.south east,anchor=west]  {short\\ text};
    \end{tikzpicture}
\end{document}

enter image description here

Skillmon
  • 60,462
  • yes, this is workaround! however, at other shapes this is not needed! also positioning libraries determine distance between shapes (as far as i understand) ... – Zarko Sep 25 '18 at 07:53
  • after testing i see new problems: vertical distance of ellipses ... see edit of my question. – Zarko Sep 25 '18 at 08:03
  • @Zarko why should positioning consider the other anchor? It does position the adequate anchor at the specified distance from the anchor you used for reference. – Skillmon Sep 25 '18 at 10:22
  • i expect that positioning of nodes works for all nodes shapes equal. but apparently it works only for rectangles. the same problem as with ellipses are with with circles. i will read manual again if this is somewhere noted. – Zarko Sep 25 '18 at 10:50
  • @Zarko it does work the same way with ellipsis as it works with rectangles. If you specify a too small distance you get a too small distance. And it doesn't consider other nodes, just the two nodes in question, the new one and the one you use as reference. – Skillmon Sep 25 '18 at 10:56
  • it seems that we not understand each other. i'm sorry for that (btw, i up-vote your answer). please continue this discussion in the chatroom. – Zarko Sep 25 '18 at 11:09
3

This is more like a comment. I do not think ellipses are special in this regard. To see that, consider the next shape of the shapes.geometric library, diamond, and compare.

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{positioning,  
                shapes}

\begin{document}
\begin{tikzpicture}[
node distance = 3mm and 9mm, % 
 block/.style = {rectangle, draw, minimum height=22mm},
 ellip/.style = {draw, ellipse, align=center},
 dia/.style = {draw, diamond, align=center},
                    ]
\node (n1) [block] {block};
\node (n2) [ellip, above right=of n1.east]  {longer text\\ in two lines};
\node (n3) [ellip, below right=of n1.east]  {short\\ text};
\begin{scope}[xshift=6cm]
\node (m1) [block] {block};
\node (m2) [dia, above right=of m1.east]  {longer text\\ in two lines};
\node (m3) [dia, below right=of m1.east]  {short\\ text};
\end{scope}
\end{tikzpicture}
\end{document}

enter image description here

In neither case the distance really is the distance to the left-most point of the shape. And I cannot find any statement in the pgfmanual suggesting that this should be so.

Here come some more remarks, suggesting that it won't be trivial to have a version of positioning that really uses the distances between extremal points.

  1. Measuring distances between extended objects is actually not completely trivial. Please look at the discussion of \pgfpointshapeborder{⟨node ⟩}{⟨point ⟩} on p. 1031 of the pgfmanual.
  2. Another complication is that the bounding box of general shapes is tricky since the points relevant to the construction of curves are also taken into account in the bounding box, see e.g. here. To the best of my knowledge, so far there is no simple way to determine a tight bounding box of complicated shapes. Of course, as Skillmon points out in his answer for unrotated ellipses one could just use the standard anchors. Yet this will fail as soon as one considers rotated ellipses. Actually, as shown by this discussion, even circles may be difficult.

As long as we do not know how to precisely determine the extremal points of arbitrary shapes, I do not see a simple way of positioning things relative to each other with fixed distances between the (unknown) extremal points.

  • no, this is not special to ellipse. i only discover this at using it. this seems to inherit to all shapes except rectangle. thank you for answer (+1). – Zarko Sep 25 '18 at 15:05
  • @Zarko You're welcome! I believe a general solution won't be trivial, and added the reasons why I think so in my answer. (of course +1 for your question, you are right that, reading the discussion of positioning, it is not 100% clear what that really does...) –  Sep 25 '18 at 15:26
  • thank you for adding valuable remarks to your answer! now i thing that the description of positioning and node distance (17.5.3 Advanced Placement Options, pages 229 -- 233) should be improved/clarified what we can expect with this library. i will wait for while if any of the package authors will add any explanation. – Zarko Sep 25 '18 at 15:53
  • @Zarko If you really could get hold of the authors, perhaps you could convince them to optionally exclude the points that are used in the path construction but not part of the path from the bounding box. This would solve many open problems at once. One could do really cool things in 3D plots, for instance. –  Sep 25 '18 at 16:11
  • This is way more than a comment. +1! – Skillmon Sep 25 '18 at 22:58
2

When you write

above right = of <point>

Tikz basically transforms this into

shift  = (<point>) + (<horizontal node distance>, <vertical node distance>)
anchor = south west

meaning that the south west anchor will be 3mm and 9mm above and right of the specified <point>. (If <point> is a node name a bit more is happening but that's beside the point.)

The anchor south west simply isn't at the most southern and most western point of the shape but at

(225: x and y)
where x and y stand for the two radii of the ellipse shape. (This also means that that point isn't actually 225° from the center.)

The two radii are calculated from the dimensions of the text box, including the inner seps, so that it tightly fits into the ellipsoid shape.

it seems that distance defined by positioning library consider "inner" text shape.

No, that's generally not true (see for example right=of …), however, the way the shape is constructed this is coincidentally true for the angles 45 (north east), 135 (nw), 225 (sw), 315 (se), i.e. above right, above left, below left and below right. But that's simply just the border of the shape.

How do you expect TikZ to handle this?


When dealing with circles (and this also applies to ellipse and similar shapes) I've found it useful to be able to use the border of a rectangle in which the circle/ellipse is tightly fitted to be used for placements.

For this I define four generic anchors that simply use the y value of the north/south anchors and the x value of the west/east anchors. This is very dumb but for the usual shapes, i.e. rectangles, circles, ellipses and those that are very similar to these, this works okay.

Here is where this points are with a circle (the rectangle connecting these four points it not part of the shape):
enter image description here

Of course, I'm lazy, so I also define the needed positioning keys:

  • corner above right,
  • corner above left,
  • corner below left and
  • corner below right

which also use the corresponding corner anchor on the reference node.

All these things (and the PGFmath functions x_node_dist/y_node_dist that I've used in the example below) are part of the ext.positioning-plus library of my tikz-ext package.


If you want the nodes to be placed, basically, at .west |- .south west more work is needed.

Code

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{positioning,shapes}
\usetikzlibrary{ext.positioning-plus}
\begin{document}
\begin{tikzpicture}[
  node distance = 3mm and 9mm,
  block/.style = {rectangle, draw, gray, minimum height=22mm},
  ellip/.style = {draw, ellipse, gray, align=center},
]
\node (n1) [block] {block};
\node (n2) [ellip, above right=of n1.east]  {longer text\\ in two lines};
\node (n3) [ellip, below right=of n1.east]  {short\\ text};

% debug \draw[densely dotted] (n2.center) -- (n2.225); \tikzset{->, nodes={node font=\tiny, fill=white, inner sep=1pt, fill opacity=.5, text opacity=1}} \draw (n2.center) -- (n2.south west) node[left, scale=.5] {\ttfamily .south west $\to$}; \draw (n3.center) -- (n3.north west) node[left, scale=.5] {\ttfamily .north west $\to$}; \draw[red] (n1.east) -| node[above, near start] {9,mm} node[right, near end] {3,mm} ++ (x_node_dist, y_node_dist); \draw[red] (n1.east) -| node[right, near end] {$-3,$mm} ++ (x_node_dist, -y_node_dist); \path [every node/.style=] node[rectangle, align=center,draw] at (n2) {longer text\in two lines}; \path [every node/.style=] node[rectangle, align=center,draw] at (n3) {short\text}; \end{tikzpicture}

\begin{tikzpicture}[ node distance = 3mm and 9mm, block/.style = {rectangle, draw, gray, minimum height=22mm}, ellip/.style = {draw, ellipse, gray, align=center}, ] \node (n1) [block] {block}; \node (n2) [ellip, corner above right=of n1.east] {longer text\ in two lines}; \node (n3) [ellip, corner below right=of n1.east] {short\ text};

% debug \tikzset{->, nodes={node font=\tiny, fill=white, inner sep=1pt, fill opacity=.5, text opacity=1}} \draw (n2.center) -- (n2.corner south west) node[left, scale=.5] {\ttfamily .corner south west $\to$}; \draw (n3.center) -- (n3.corner north west) node[left, scale=.5] {\ttfamily .corner north west $\to$}; \draw[red] (n1.east) -| ++ (x_node_dist, y_node_dist); \draw[red] (n1.east) -| ++ (x_node_dist, -y_node_dist); \end{tikzpicture} \end{document}

Output (your code)

enter image description here

Output (with corner anchors)

enter image description here

Qrrbrbirlbel
  • 119,821
  • Thank you very much for exhaustive answer! I will need some time to acquire recent version of your library as well to test it and figured out your explanation. So for now +1 – Zarko Oct 17 '22 at 13:57