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

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

  • 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 '15 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 '15 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 '15 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 '15 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 '15 at 13:48
3

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

  • You don't understand why what is necessary? – picasso Jan 2 '15 at 3:03
  • 1
    @iab I don't understand why your code doesn't work. – cfr Jan 2 '15 at 3:14
  • @cfr What if I want to bidirectional arrow between two boxes – new_born Jan 29 '18 at 12:55
  • @new_born Use <-> rather than -> or <-? – cfr Jan 29 '18 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.