Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

There should be an easy way to place a sloped node along a path. Using sloped works great (as in the black text). However, if there is a rotate= applied then the text is no longer along the path (as in the red and blue examples). I can get the correct direction if I use transform shape (as in the orange example), but then the text gets scaled if a scale= is being applied.

Question: How do I define the \MyDraw macro so that it can be used with a rotate and a scale such that:

  • the text is along the path even if a rotate= is applied, and
  • the text is not affected by a scale=.

enter image description here

Notes:

  • In my actual use, these drawing are all in the same tikzpicture and I use a scope to apply the desired transformations. To keep the MWE as close to possible as my actual use case, I used scopes in the MWE below instead of applying the options to the tikzpicture itself.

Code:

\documentclass{article}
\usepackage{tikz}

\newcommand*{\MyDraw}[1]{%
    \draw [ultra thick, -latex] (0,0) -- (1,4) 
        node [midway, above, sloped, align=center] {#1};
}%

\begin{document}
\begin{tikzpicture}
    \MyDraw{not rotated};
\end{tikzpicture}%
% --------------------------------- apply "rotation"
\begin{tikzpicture}
    \begin{scope}[rotate=-25, red]
        \MyDraw{rotated};
    \end{scope}
\end{tikzpicture}%
% --------------------------------- apply "rotation" and "scale"
\begin{tikzpicture}
    \begin{scope}[rotate=-15, scale=1.3, blue]
        \MyDraw{rotated and scaled};
    \end{scope}
\end{tikzpicture}%
% --------------------------------- apply "rotation", "scale" and "transform shape"
\begin{tikzpicture}
    \begin{scope}[rotate=-15, scale=1.5, transform shape, orange]
        \MyDraw{rotated, scaled and \\ ``transform shape"};
    \end{scope}
\end{tikzpicture}
\end{document}
share|improve this question
    
Using this answer to question 162639, you could use \pgfgettransformentries{\mya}{\myb}{\myc}{\myd}{\mys}{\myt} to guess the scale factor and then use it together with the transform shape key with xscale=1/\mya,yscale=1/\myd. It is working in your example, but I wonder if it will works in every cases (I mean with multiple transformations). –  remjg Jun 10 at 21:00
    
@remjg: Yep, that works well along with transform shape. You want to post that as an answer - I am going to use that unless an easier solution appears. –  Peter Grill Jun 10 at 21:11
1  
@remjg: Upon further testing it appears that that is not very precise. I tested it using the "unscaling" the text via the exact scale that I am applying and the size of the text is different as compared to using mya and myd. –  Peter Grill Jun 10 at 21:19

3 Answers 3

Use nodes={rotate=<angle>} instead transform shape:

In contrast to transform shape the nodes={rotate=<angle>} passes only the transformation selected by its argument (i.e. rotate=<angle>) to all nodes inside the scope.

Defining a new style myrotate as an abbreviation

\tikzset{
  myrotate/.style={rotate=#1,nodes={rotate=#1}}
}

and using myrotate=<angle> instead rotate=<angle> results in

enter image description here

Code:

\documentclass{article}
\usepackage{tikz}
\tikzset{
  myrotate/.style={rotate=#1,nodes={rotate=#1}}
}

\newcommand*{\MyDraw}[1]{%
    \draw [ultra thick, -latex] (0,0) -- (1,4) 
        node [midway, above, sloped, align=center] {#1};
}%

\begin{document}
\begin{tikzpicture}
    \MyDraw{not rotated};
\end{tikzpicture}%
% --------------------------------- apply "rotation"
\begin{tikzpicture}
    \begin{scope}[myrotate=-25,red]
        \MyDraw{rotated};
    \end{scope}
\end{tikzpicture}%
% --------------------------------- apply "rotation" and "scale"
\begin{tikzpicture}
    \begin{scope}[myrotate=-15,scale=1.3, blue]
        \MyDraw{rotated and scaled};
    \end{scope}
\end{tikzpicture}%
% --------------------------------- apply "rotation", "scale" and "transform shape"
\begin{tikzpicture}
    \begin{scope}[myrotate=-15, scale=1.5, orange]
        \MyDraw{rotated, scaled and \\ ``transform shape"};
    \end{scope}
\end{tikzpicture}
\end{document}
share|improve this answer
    
Not sure if this solution will work for me as it require to pass the rotate information to every component of the figure. But as far as rotate not affecting a node, if you apply transform shape then you don't need to manually apply a rotate to the node. –  Peter Grill Jun 11 at 7:33
    
If you use transform shape the nodes will also be scaled. But it is possible to use every node/.append style to pass the rotate option to all nodes inside the scope. I have edited my answer. –  esdd Jun 11 at 7:57

I used to write a linear algebra library for TikZ(mainly to handle complex numbers) but since now TikZ is using Lua extensively that became pretty much obsolete so I stopped it. Nevertheless here is a quick steal from the Givens QR decomposition for two by two matrix that separates the transformation matrix into scaling and rotation and we only use rotation part and omit the scale/slant part.

Same idea can be used to cancel the rotation and keep the scaling to answer the question in the comments. I'll have a look if I can spare more time.

\documentclass{article}
\usepackage{tikz}

\newcommand*{\MyDraw}[1]{%
    \draw [ultra thick, -latex] (0,0) -- (1,4) 
        node [midway, above, sloped, align=center,cancel scale] {#1};
}%
\tikzset{cancel scale/.code=\pgfmathcancelscale}

\makeatletter
\def\pgfmathcancelscale{%
  \pgfgettransformentries{\my@a}{\my@b}{\my@c}{\my@d}{\my@xi}{\my@yi}%
  \pgfmathsetmacro\my@cos{\my@a/veclen(\my@a,\my@c)}%
  \pgfmathsetmacro\my@sin{-\my@c/veclen(\my@a,\my@c)}%
  \pgfsettransformentries{\my@cos}{\my@sin}{-\my@sin}{\my@cos}{\my@xi}{\my@yi}%
}
\makeatother

\begin{document}

\begin{tikzpicture}
    \begin{scope}[rotate=-15, scale=1.5, transform shape, orange]
        \MyDraw{rotated, scaled and \\ ``transform shape"};
            \begin{scope}[rotate=40, scale=0.2, shift={(10cm,-5cm)},transform shape, blue]
            \MyDraw{rotated, scaled and \\ ``transform shape"};
            \end{scope}
    \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
This works well except that it also affects the placement of the text, and hence requires manually moving the text. –  Peter Grill Jun 10 at 21:58
    
@PeterGrill Oops. I just saw that :) Let me see –  percusse Jun 10 at 21:58
    
@PeterGrill It's because of the timer gets also affected (which controls the pos=<num> stuff). I have to isolate it but it will be some time later :) –  percusse Jun 10 at 22:47
    
This would be an ideal solution if the node placement wasn't so out of whack. –  Peter Grill Jun 13 at 18:45
    
@PeterGrill I'm getting there slowly. It took some time to get what is happening. I need to hack in somewhere. Don't know yet :) –  percusse Jun 13 at 19:42

As a follow up to my comment, here is what I have tried using this answer from the question Access the scale option within TikZ environment.

I would define a new key Sloped that guess the xscale and yscale factor to cancel scaling while using sloped and transform shape to keep the rotation:

\tikzset{
  Sloped/.code=%
  \pgfgettransformentries{\mya}{\myb}{\myc}{\myd}{\mys}{\myt}%
  \tikzset{sloped, transform shape, xscale=1/\mya, yscale=1/\myd}%  
}

Code

\documentclass[margin=0.5cm]{standalone}
\usepackage{tikz}

\tikzset{%
  Sloped/.code=%
  \pgfgettransformentries{\mya}{\myb}{\myc}{\myd}{\mys}{\myt}%
  \tikzset{sloped, transform shape, xscale=1/\mya, yscale=1/\myd}%  
}%

\newcommand*{\MyDraw}[1]{%
    \draw [ultra thick, -latex] (0,0) -- (70:5) 
        node [midway, above, Sloped, align=center] {#1};
}%

\begin{document}
  \begin{tikzpicture}
      \MyDraw{not rotated};
  \end{tikzpicture}%
  %--------------------------------- apply "rotation"
  \begin{tikzpicture}
      \begin{scope}[rotate=-25, red]
          \MyDraw{rotated};
      \end{scope}
  \end{tikzpicture}%
  % --------------------------------- apply "rotation" and "scale"
  \begin{tikzpicture}
      \begin{scope}[rotate=-15, scale=1.3, blue]
          \MyDraw{rotated and scaled};
      \end{scope}
  \end{tikzpicture}%
  % --------------------------------- apply "rotation", "scale" and "transform shape"
  \begin{tikzpicture}
      \begin{scope}[rotate=-15, scale=1.5, transform shape, orange]
          \MyDraw{rotated, scaled and \\ ``transform shape"};
      \end{scope}
  \end{tikzpicture}
\end{document}

Output

Output

Problem

As mentioned by Peter Grill in the comment, it doesn't work very well, the text is a bit smaller. I remove my answer as soon as someone tell me why it doesn't work ;-)

Problem comparing with the exact output

share|improve this answer
1  
That's indeed the way to go for pure scaling but it doesn't work with slanted versions. And don't remove it. It's nice : ) That much TeX arithmetic is acceptable –  percusse Jun 10 at 22:02
    
I don't understand the difference between scaling and slanted, can you shed some light on this? –  remjg Jun 11 at 19:17
1  
add yslant=0.4 etc. to see the effect. They are the off diagonal terms in the transformation matrix. So if you have [2 0.5;0 3] as the transformation matrix multiplying the coordinate [x;y], that means multiply x by two and add half of y to it. So things get parallelogramed as the scaling is not purely xscale=2,yscale=3if something else sets a trafo matrix, @esdd answer also goes awry. –  percusse Jun 11 at 19:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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