14

The following code

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.11}
\usetikzlibrary{arrows,backgrounds,patterns,shapes.geometric,calc,positioning}
\tikzset{small dot/.style={fill=black,circle,outer sep=8pt,scale=0.25}}

\begin{document}

\begin{tikzpicture}[scale=0.8]
    \draw[ultra thin,color=lightgray] (-4,-2) grid (7,5);   % coordinate grid
    \draw[<->] (-4.5,0) -- (7.5,0) node[right] {$x$};   % x-axis
    \draw[<->] (0,-2.5) -- (0,5.5) node[above] {$y$};   % y-axis

    \foreach \x/\xtext in {-4,...,-1,1,2,..., 7}        % x-axis labels
        \draw (\x cm,2pt) -- (\x cm,-2pt) node[anchor=north, font=\footnotesize] {$\xtext$}; 

    \foreach \y/\ytext in {-2, -1,1,2,..., 5}           % y-axis labels
        \draw (2pt,\y cm) -- (-2pt,\y cm) node[anchor=east, font=\footnotesize] {$\ytext$}; 

    % parametric function alpha(t)
        \draw [thick, samples=1000] plot[parametric, domain=0:2*pi, id=spiral] function{t*cos(t),-t*sin(t)};

    % points on graph
    \foreach \t in {0, 30, ..., 360}
        \filldraw ({(\t*3.14/180)*cos(\t)},{-(\t*3.14/180)*sin(\t)}) circle (2pt);

    % position vectors
    \foreach \t in {0, 30, ..., 360}
        \draw[->, color=blue, thin] (0,0) -- 
            ({(\t*3.1/180)*cos(\t)},{-(\t*3.1/180)*sin(\t)});

    %tangent vectors
    \foreach \t in {0, 30, ..., 360}
        \draw[->, color=red, dashed, very thin] ({(\t*3.14/180)*cos(\t)},{-(\t*3.14/180)*sin(\t)}) --
        +({-(\t*3.14/180)*sin(\t) + cos(\t)}, {-(\t*3.14/180)*cos(\t) - sin(\t)});

\end{tikzpicture}
\end{document}

produces exactly what I need for the moment:

Spiral with position and tangent vectors

I am generating a parametric curve, then drawing position and tangent vectors at various points. I have read through this, this, this, this, this, and this, and, in particular, this answer to a related question was very helpful. I still have a couple questions about doing this more efficiently.

First, is there a way to store coordinates along the curve at various points, then re-use those to create the position and tangent vectors? For example, I'd like to compute and store something like

\foreach \t in {0, 0.5236, ..., 6.28}
    \x = {x(t)}
    \y = {y(t)}

in an array, where x(t) and y(t) are the position functions. I would then use those stored values to create the position vectors as

\for each (\x, \y) in [position array]
    \draw[->, color=blue, thin] (0,0) -- (\x,\y);

Similar, for the velocity vectors, I would compute

\foreach \t in {0, 0.5236, ..., 6.28}
    \deltax = {x'(t)}
    \deltay = {y'(t)}

and create velocity vectors

\for each (\x, \y) in [position array]
    \draw[->, color=blue, thin] (\x,\y) -- + (\deltax, \deltay);

where (\deltax,\deltay) is indexed to match with the appropriate (\x,\y) position vector.

I have read where pgf / tikz stores gnuplot coordinates in a .table file, but I can't figure out how to access them to do this.

Secondly, I discovered that cos(\t) and sin(\t) are using \t in degrees, so I had to manually convert to radians for the magnitude of the vectors. There has to be a better way to do this? The code

\foreach \t in {0, 30, ..., 360}
\pgfmathparse{rad(\t)}
\draw[->, color=blue, very thin] (0,0) -- 
    ({\pgfmathresult*cos(\t)},{-\pgfmathresult*sin(\t)});

does not work.

1
  • \pgfmathresult is used a lot by TikZ itself. You need to store it using, for example, \let\radius=\pgfmathresult before any other TikZ commands. Jul 19, 2015 at 21:00

4 Answers 4

9

Here is a solution where:

  • (f-\t) is a point on the curve,

  • (f'-\t) is the associate tangent vector.

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

\begin{document}
\begin{tikzpicture}
  \draw[ultra thin,color=lightgray] (-4,-2) grid (7,5);   % coordinate grid
  \draw[<->] (-4.5,0) -- (7.5,0) node[right] {$x$};   % x-axis
  \draw[<->] (0,-2.5) -- (0,5.5) node[above] {$y$};   % y-axis

  \foreach \x/\xtext in {-4,...,-1,1,2,...,7}        % x-axis labels
  \draw (\x,2pt) -- (\x,-2pt) node[anchor=north, font=\footnotesize] {$\xtext$}; 

  \foreach \y/\ytext in {-2, -1,1,2,..., 5}           % y-axis labels
  \draw (2pt,\y) -- (-2pt,\y) node[anchor=east, font=\footnotesize] {$\ytext$}; 

  % parametric function alpha(t)
  \draw [thick, samples=50,smooth] plot[variable=\t, domain=0:2*pi] ({\t*cos(\t r)},{-\t*sin(\t r)});

  % points and tangent
  \foreach \t in {0, 30, ..., 360}{
    \pgfmathsetmacro\radius{rad(\t)}
    \pgfmathsetmacro\st{sin(\t)}
    \pgfmathsetmacro\ct{cos(\t)}
    \path
    ({\radius*\ct},{-\radius*\st}) coordinate (f-\t)
    ({-\radius*\st+\ct},{-\radius*\ct-\st}) coordinate (f'-\t);
  }

  % draw points, radii and vectors
  \foreach \t in {0,30,...,360}{
    \fill (f-\t) circle (2pt);
    \draw[->, color=blue, thin] (0,0) -- (f-\t);
    \draw[->, color=red, dashed, very thin] (f-\t) -- ++(f'-\t);
  }
\end{tikzpicture}
\end{document}

Edit

Here is a variant using TikZ library math and where each point is named by its order number instead of its angle position.

enter image description here

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}
  \draw[ultra thin,color=lightgray] (-4,-2) grid (7,5);   % coordinate grid
  \draw[<->] (-4.5,0) -- (7.5,0) node[right] {$x$};   % x-axis
  \draw[<->] (0,-2.5) -- (0,5.5) node[above] {$y$};   % y-axis

  \foreach \x/\xtext in {-4,...,-1,1,2,...,7}        % x-axis labels
  \draw (\x,2pt) -- (\x,-2pt) node[anchor=north, font=\footnotesize] {$\xtext$}; 

  \foreach \y/\ytext in {-2, -1,1,2,..., 5}           % y-axis labels
  \draw (2pt,\y) -- (-2pt,\y) node[anchor=east, font=\footnotesize] {$\ytext$}; 

  % parametric function alpha(t)
  \draw [thick, samples=50,smooth] plot[variable=\t, domain=0:2*pi] ({\t*cos(\t r)},{-\t*sin(\t r)});

  % points and tangent
  \tikzmath{
    integer \c; \c = 0;
    for \t in {30,60,...,360}{
      \c = \c + 1;
      \radius = rad(\t);
      \st = sin(\t);
      \ct = cos(\t);
      {
        \path
        ({\radius*\ct},{-\radius*\st}) coordinate (f-\c)
        ({-\radius*\st+\ct},{-\radius*\ct-\st}) coordinate (f'-\c);
      };
    };
  }

  % draw points, radii and vectors
  \foreach \c in {1,...,12}{
    \draw[->, color=blue, thin] (0,0) -- (f-\c);
    \draw[->, color=red, dashed, very thin] (f-\c) -- ++(f'-\c);
    \path (f-\c) node[text=white,circle,minimum size=8pt,inner sep=0,fill=black,font=\tiny]{\c};
  }
\end{tikzpicture}
\end{document}
1
  • Thank you. It was difficult to choose out of all the solutions, as they were all fantastic. I chose this one because I really like the modification of showing the vectors in sequence (I was planning on doing this). At the same time, I believe @moospit's solution may be more of what I was seeking in terms of compactness. I am going to play around with all of the suggestions. Jul 22, 2015 at 17:35
6

Except for the missing gnuplot file, this works:

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\usetikzlibrary{arrows,backgrounds,patterns,shapes.geometric,calc,positioning}
\tikzset{small dot/.style={fill=black,circle,outer sep=8pt,scale=0.25}}

\begin{document}

\begin{tikzpicture}[scale=0.8]
    \draw[ultra thin,color=lightgray] (-4,-2) grid (7,5);   % coordinate grid
    \draw[<->] (-4.5,0) -- (7.5,0) node[right] {$x$};   % x-axis
    \draw[<->] (0,-2.5) -- (0,5.5) node[above] {$y$};   % y-axis

    \foreach \x/\xtext in {-4,...,-1,1,2,..., 7}        % x-axis labels
        \draw (\x cm,2pt) -- (\x cm,-2pt) node[anchor=north, font=\footnotesize] {$\xtext$}; 

    \foreach \y/\ytext in {-2, -1,1,2,..., 5}           % y-axis labels
        \draw (2pt,\y cm) -- (-2pt,\y cm) node[anchor=east, font=\footnotesize] {$\ytext$}; 

    % parametric function alpha(t)
    \draw [thick, samples=1000] plot[parametric, domain=0:2*pi, id=spiral] function{t*cos(t),-t*sin(t)};

    % points on graph
    \foreach \t in {0, 30, ..., 360}
        {\pgfmathparse{\t*3.141592653589793/180}
        \let\radius=\pgfmathresult
        \coordinate (P\t) at ({\radius*cos(\t)},{-\radius*sin(\t)});
        \filldraw (P\t) circle (2pt);}

    % position vectors
    \foreach \t in {0, 30, ..., 360}
        \draw[->, color=blue, thin] (0,0) -- (P\t);

    %tangent vectors
    \foreach \t in {0, 30, ..., 360}
        \draw[->, color=red, dashed, very thin] (P\t) -- +($(0,0)!1!-90:(P\t) + ({cos(\t)},{-sin(\t)})$);}
\end{tikzpicture}
\end{document}
4

Here an approach using the evaluate option of the foreach loop. Using this you can create the whole plot in one loop and pre-calculate all needed values.

The coordinates on the plot are saved via coord-\x and can be reused. All the calculations are done via evaluate.

I think the code is quite self-explanatory. If you still got questions, feel free to ask.

\documentclass[tikz, border=6mm]{standalone}

\begin{document}
  \begin{tikzpicture}[>=latex]
    % Axis
    \draw [black!25, thin] (-4,-2) grid (7,5);
    \draw [<->] (-4.5,0) -- (7.5,0) node [right] {$x$};
    \draw [<->] (0,-2.5) -- (0,5.5) node [above] {$y$};
    \foreach \x in {-4,...,-1,1,2,...,7} {
        \draw (\x,2pt) -- (\x,-2pt) node [below] {$\x$};
        \ifnum\x>-3\ifnum\x<6
            \draw (-2pt,\x) -- (2pt,\x) node [left=.25cm] {$\x$};
        \fi\fi
    }

    % Plot
    \draw [thick, smooth, domain=0:2*pi] plot ({\x*cos(\x r)}, {-\x*sin(\x r)});
    \foreach \x [
        evaluate=\x as \rx using \x*pi/180, %
        evaluate=\rx as \rsin using \rx*sin(\x), %
        evaluate=\rx as \rcos using \rx*cos(\x), %
        evaluate=\x as \sin using sin(\x), %
        evaluate=\x as \cos using cos(\x)] in {30, 60,...,360} {
            \fill (\rcos, -\rsin) circle (2pt) coordinate (coord-\x);
            \draw [blue, ->] (0,0) -- (coord-\x);
            \draw [red, dashed, ->] (coord-\x) -- +({-\rsin+\cos}, {-\rcos-\sin});
    }
    \fill [blue] (0,0) circle (2pt);
  \end{tikzpicture}
\end{document}

rendered image

3

Another example using the math library. This illustrates the use of the r operator which is a post-fix operator which converts the preceding number to degrees. Also, points and derivatives are stored as coordinate macros.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{math}
\tikzmath{
  coordinate \c, \d;
  integer \n;
  \n = 0;
  for \t in {0, pi/6, ..., 2*pi}{
    \n = \n + 1;
    \a = \t r;
    \c{\n} = (\t * cos \a, -\t * sin \a); 
    \d{\n} = (cos \a - \t * sin \a, -sin \a - \t * cos \a); 
  };
} 
\begin{document}
\begin{tikzpicture}[>=stealth]
\draw [ultra thin, color=lightgray] (-4,-2) grid (7,5); 
\draw [<->] (-4.5,0) -- (7.5,0) node[right] {$x$};
\draw [<->] (0,-2.5) -- (0,5.5) node[above] {$y$};
\foreach \x/\xtext in {-4, -3, ..., 7}
  \draw (\x,2pt) -- (\x,-2pt) node [anchor=north, font=\footnotesize] {$\xtext$}; 
\foreach \y/\ytext in {-2, -1, ..., 5} 
  \draw (2pt,\y) -- (-2pt,\y) node [anchor=east, font=\footnotesize] {$\ytext$}; 

\draw [thick, samples=250] plot [smooth, domain=0:2*pi, variable=\t] 
  ({\t*cos(\t r)},{-\t*sin(\t r)});
\foreach \i in {2,...,\n}{
  \draw [blue, shorten >=2pt, ->] (0, 0) -- (\c{\i});
  \draw [red, dashed, ->]  (\c{\i}) -- (\cx{\i}+\dx{\i}, \cy{\i}+\dy{\i});
  \fill (\c{\i}) circle [radius=2pt];
}
\end{tikzpicture}
\end{document}

enter image description here

You must log in to answer this question.

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