10

I am trying to draw a straight arrow from one shape to another, two rectangles precisely. I have an MWE below, but the arrow from rectangle B meets rectangle A at an angle instead of at 90 degrees.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\usepackage{graphicx}

\begin{document}
\begin{tikzpicture}

\tikzstyle{block}=[draw,shape=rectangle,minimum width=3.5em,text width=1.7cm,align=center,minimum height=1.2cm, node distance=3cm]

\node[block] (A) at (0,0) {A};
\node[block,right of=A] (B) {B};
\draw[->] ([yshift=-2em] B) -- ([yshift=-2em] A);

\end{tikzpicture}

\end{document}

What I am trying to achieve:

enter image description here

3
  • Do you really want a moved down arrow? Instead of simply \draw[->] (B)--(A);?
    – Sigur
    Jan 2, 2015 at 2:07
  • @Sigur Why doesn't it work, though?
    – cfr
    Jan 2, 2015 at 2:28
  • @Sigur Yes, I really do want a moved down arrow.
    – picasso
    Jan 2, 2015 at 2:59

3 Answers 3

9

This looks like a bug for me.

In a strange way if we use ([transform] A) when A is a node, the anchor to, or from, A is calculated before the transformation, and the node A is transformed only afterwards.

In your example :

  1. the anchor to A is calculated, and not to ([yshift=-2em] A), from the shifted B (or more precisely from ([yshift=-2em] B.center));
  2. the anchor from B is calculated, not from ([yshift=-2em] B), to the calculated anchor of A.

Here is an illustration of this.

\documentclass[tikz,border=10]{standalone}
\tikzset{
  block/.style = {draw, minimum width=1.7cm, minimum height=1.2cm, node distance=3cm},
  down/.style={yshift=-7em}
}

\begin{document}
  \begin{tikzpicture}
    % "almost" the original code
    \node[block] (A) at (0,0) {A};
    \node[block,right of=A] (B) {B};
    \draw[->] ([down] B) -- ([down] A)  -- ([down] B);

    % illustration of the anchor calculation
    \begin{scope}[red]
      \node[block] (A2) at ([down] A) {A2};
      \node[block] (B2) at ([down] B) {B2};
      \draw[->] (B2) -- (A);
    \end{scope}

    % and more examples
    \begin{scope}[blue]
      \draw[->] ([down] B) -- ([down] A.east);
      \draw[->] ([down] B.west) -- ([down] A);
    \end{scope}
  \end{tikzpicture}
\end{document}

enter image description here

In conclusion : We can't transform nodes like this, only "real" coordinates are transformed.

Workaround: You can use transform canvas to do your shifts like this :

    \begin{scope}[ transform canvas={yshift=-2em}]
      \draw[->] (B) -- (A);
    \end{scope}

In your particular MWE a workaround will be also to specify the anchors like this :

\draw[->] ([yshift=-2em] B.west) -- ([yshift=-2em] A.east); 

UPDATE: Actually ([transformed] A) looks to have a "double nature" : as a coordinate it is the same as ([transformed] A.center) and as a node it is the same as (A). Here is one example that shows this "double behavior" of coordinate transformed nodes.

\documentclass[tikz,border=10]{standalone}
\tikzset{
  block/.style = {draw,minimum width=1.7cm, minimum height=1.2cm, node distance=3cm}
}

\begin{document}
  \begin{tikzpicture}
    \node[block, circle] (A) at (0,0) {A};
    \node[block,right of=A] (B) {B};

    % ([yshift=-2em] A) behaves like the node (A)
    \foreach \i in {0,30,...,360}
        \draw[blue, ->] (\i:2) -- ([yshift=-2em] A);

    % ([rotate=\i]B) behaves like the point ([rotate=\i]B.center) to calculate the anchor of (A)
    % and then behaves like the node (B) when we draw from it.
    \foreach \i in {0,30,...,360}
      \draw[red,->] ([rotate=\i]B) -- (A);
  \end{tikzpicture}
\end{document}

enter image description here

11
  • This is helpful and I agree it looks like a bug. However, I'm finding it rather difficult to follow. I reworded a little bit at the top, where I was confident that I understood your intended meaning (but obviously you should roll back if not). But I get a bit lost after that. I find the part where you offer a workaround and then add a note and conclusion especially confusing. Is the note supporting the workaround? Or are you saying the workaround doesn't work? Apologies for my slowness!
    – cfr
    Jan 2, 2015 at 12:58
  • @cfr thanks for your edit (and happy new year)! I removed the note and merged it with the "update" (I have updated this answer more then 10 times :(). And I moved the conclusion before the workaround. Is like this more readable ? If not, feel free to edit it.
    – Kpym
    Jan 2, 2015 at 13:10
  • (+1) That seems much clearer to me now. It is complex because the subject matter is complex, but it flows a lot more logically - especially switching the workaround and the conclusion. That makes much better sense to me now.
    – cfr
    Jan 2, 2015 at 13:14
  • This is really weird, isn't it? It seems like a bug, but it is surprising to me that people have not triggered it before, if so.
    – cfr
    Jan 2, 2015 at 13:14
  • 1
    @cfr We triggered it. You need to use A.center, B.center but not A,B if you want to add transformations on the path. Because the former ones are coordinates, the latter ones are node names. And transformations apply on coordinates.
    – percusse
    Jan 4, 2015 at 13:48
4

I don't understand why this is necessary, but a workaround might be:

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{positioning}
\begin{document}

  \begin{tikzpicture}
    [block/.style={
      draw,
      shape=rectangle,
      minimum width=3.5em,
      text width=1.7cm,
      align=center,
      minimum height=1.2cm,
      node distance=3cm}
    ]

    \node[block] (A) at (0,0) {A};
    \node[block, right=of A] (B) {B};% new syntax is recommended using the positioning library
    \draw[->] (B) -- (A);% for comparison only
    \draw[->] (B.west) +(0,-1em) coordinate (b1) -- (A.east |- b1);
  \end{tikzpicture}

\end{document}

lowered arrow

4
  • You don't understand why what is necessary?
    – picasso
    Jan 2, 2015 at 3:03
  • 1
    @iab I don't understand why your code doesn't work.
    – cfr
    Jan 2, 2015 at 3:14
  • @cfr What if I want to bidirectional arrow between two boxes
    – new_born
    Jan 29, 2018 at 12:55
  • @new_born Use <-> rather than -> or <-?
    – cfr
    Jan 29, 2018 at 23:04
1

A PSTricks solution where you have to choose the dimensions of the two boxes and the length of the arrow:

\documentclass{article}

\usepackage{pstricks}
\usepackage{xfp}

\newcommand*\pictureWidth{\fpeval{\widthA+\arrowLength+\widthB}}
\newcommand*\pictureHeight{\fpeval{max(\heightA,\heightB)}}

\begin{document}

% dimensions of the first box
\def\widthA{2}
\def\heightA{1}
% length of the arrow
\def\arrowLength{2}
% dimensions of the second box
\def\widthB{2.5}
\def\heightB{1.5}
% the picture
\begin{pspicture}(\pictureWidth,\pictureHeight)
  \psframe(0,0)(\widthA,\heightA)
  \rput(\fpeval{\widthA/2},\fpeval{\heightA/2}){A}
  \psline{->}%
    (\fpeval{\widthA+\arrowLength},\fpeval{4/15*(\heightA+\heightB)/2})%
    (\widthA,\fpeval{4/15*(\heightA+\heightB)/2})
  \psframe(\fpeval{\widthA+\arrowLength},0)(\fpeval{\widthA+\arrowLength+\widthB},\heightB)
  \rput(\fpeval{\widthA+\arrowLength+\widthB/2},\fpeval{\heightB/2}){B}
\end{pspicture}

\end{document}

output

You must log in to answer this question.

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