0

In journal papers, I often see annotations in figures depicting triangles with certain slopes to emphasize which slopes the different graphs in the figure (approximately) have.

For example

Is there a macro in LaTeX to make such annotations easily? So, given a relative position in the axis and a slope, a triangle with this slope is plotted at the relative position in the axis?

Adriaan
  • 3,675
  • 2
  • 21
  • 41

2 Answers2

2
% Mind section '4.17 Custom annotations' of the PGFplots manual Revision 1.12 (2015/01/31).
\documentclass[margin=1cm]{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=newest}

%%% START MACRO %%%
\newcommand{\slopeTriangle}[5]
{
    % #1. Relative offset in x direction.
    % #2. Width in x direction, so xA-xB.
    % #3. Relative offset in y direction.
    % #4. Slope dydx.
    % #5. Plot options.

    \pgfplotsextra
    {
        \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
        \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
        \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
        \pgfkeysgetvalue{/pgfplots/ymax}{\ymax} 

        % Calculate auxilliary quantities.
        \pgfmathsetmacro{\xA}{\xmin+(#1+#2)*(\xmax-\xmin)}
        \pgfmathsetmacro{\yA}{\ymin+#3*(\ymax-\ymin)}
        \pgfmathsetmacro{\xB}{\xmin+#1*(\xmax-\xmin)}
        \pgfmathsetmacro{\yB}{\yA}
        \pgfmathsetmacro{\xC}{\xA}
        \pgfmathsetmacro{\yC}{\yA+(\xA-\xB)*#4}

        % Define coordinates for \draw.
        \coordinate (A) at (axis cs:\xA,\yA);
        \coordinate (B) at (axis cs:\xB,\yB);
        \coordinate (C) at (axis cs:\xC,\yC);

        % Draw slope triangle.
        \draw[#5]   (A)-- node[pos=0.5,anchor=north] {1}
                    (B)-- 
                    (C)-- node[pos=0.5,anchor=west] {#4}
                    cycle;
    }
}
%%% END MACRO %%%

\begin{document}
    \begin{tikzpicture}
        \begin{axis}
        [
            xtick={-0.1,0,1,1.1},
            xlabel=$x$,
            ytick={-0.2,0,2,2.2},
            ylabel style={rotate=-90},
            ylabel=$y$,
            unit vector ratio=2 1 1,
            clip=false
        ]
            \addplot[blue,domain=0:1] {x};
            \addplot[red,domain=0:1] {2*x};

            \slopeTriangle{0.65}{0.1}{0.1}{1}{blue}; % USE OF MACRO.
            \slopeTriangle{0.825}{0.1}{0.1}{2}{red}; % USE OF MACRO.
        \end{axis}
    \end{tikzpicture}
\end{document}

Adriaan
  • 3,675
  • 2
  • 21
  • 41
2

A MetaPost solution. It happens that I have already devised such a macro for a course I'm currently teaching, which can be applied to any function curve. Here it is, slightly modified and applied to the parabola y = 4x-x^2. The slopes are computed by MetaPost itself and rounded to an arbitrary number of digits with the help of the numprint package. (Since the slopes are known here to have integer values, I've instructed numprint to round them to the nearest integer: \nprounddigits{0}, but it can be changed at will.)

The MetaPost coding has been inserted in a LuaLaTeX program for better convenience:

\documentclass[border=2mm]{standalone}
\usepackage{luamplib}
  \mplibsetformat{metafun}
  \mplibtextextlabel{enable}
  \mplibnumbersystem{double}
\usepackage{numprint}
  \nprounddigits{0}
\begin{document}
  \begin{mplibcode}
    input mpcolornames; 
    % Parameters
    numeric u, v, xmin, xmax, xstep, ymin, ymax;
    u = v = 1cm; xmin = -2; xmax = 6; xstep = 0.1;
    ymin = -6; ymax = 6;
    % Graph definition
    vardef f (expr x) = 4x - x**2 enddef;
    path my_graph; 
    my_graph = function(2, "x", "f(x)", xmin, xmax, xstep);
    % Macro creating triangle with slope
    def triangle_with_slope(expr p, A) =
      % Basis and height
      h := 1; a := xpart A; b := a + h;
      % Direction
      pair vdir, B; 
      vdir = direction ((a-xmin)/xstep) of p; 
      B = A + vdir/xpart(vdir);
      % tangent and triangle
      path tangente, Delta_x, Delta_y, triangle; 
      Delta_x = (A -- (xpart B, ypart A)) xyscaled (u, v);
      Delta_y = ((xpart B, ypart A) -- B) xyscaled (u, v);
      tangente = (A -- B) xyscaled (u, v);      
      triangle = (A -- (xpart B, ypart A) -- B -- cycle) xyscaled (u, v);
      % The drawing
      drawoptions(withcolor DarkRed);
      fill triangle withcolor Pink; draw tangente;
      drawarrow Delta_x; drawarrow Delta_y;
      drawdot A xyscaled (u, v) withpen pencircle scaled 3bp;
      % Labels
      string slope; slope := decimal(ypart(B-A));
      labeloffset := 2bp;
      label. if ypart(B-A)>0: bot else: top fi ("$1$", point .5 of Delta_x);
      freelabel("$\numprint{" & slope & "}$", point .5 of Delta_y, center triangle);
      drawoptions( );
    enddef;
    beginfig(1);
      % Axes        
      drawarrow (xmin*u, 0) -- (xmax*u, 0);
      drawarrow (0, ymin*v) -- (0, ymax*v);
      % Graph and triangles with slope
      for i = -1 upto 4: triangle_with_slope(my_graph, (i, f(i))); endfor
      picture parabola; parabola = image(draw my_graph xyscaled (u, v));
      clip parabola to 
        ((xmin, ymin) -- (xmax, ymin) -- (xmax, ymax) -- (xmin, ymax) -- cycle) 
          xyscaled (u, v); 
      draw parabola;
      % Marks
      labeloffset := 5bp;
      label.bot("$x$", (xmax*u, 0)); label.lft("$y$", (0, ymax*v));
      for i = -2 upto 5: if i<>0: draw (i*u, -3bp) -- (i*u, 3bp); fi endfor
      for j = -6 upto 5: if j<>0: draw (-3bp, j*v) -- (3bp, j*v); fi endfor
      label.bot("$1$", (u, 0)); label.lft("$1$", (0, v));
    endfig;
  \end{mplibcode}
\end{document}

Output:

enter image description here

Franck Pastor
  • 18,756