6

I would like to draw the left panel (in which I placed the blue curve manually). But in the right panel the curve is different. How can I draw the curve as shown in the left panel (without manually calculating the position of the blue curve)?

Related question, how can I get the tangential coordinate system (using scope) whose x-axis is the black tangent line and origin is the marked point?

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\usetikzlibrary{decorations.markings}

\tikzset{
  tangent pos/.style={decoration={markings, mark = at position #1 with {
        \coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
        \coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
        \coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
      }
    },
    postaction=decorate
  },
  %
  tangent/.style={shift=(tangent point-#1), x=(tangent unit vector-#1), y=(tangent orthogonal unit vector-#1)},
}

\newcommand*{\tpointmark}[2][]{\fill [smooth,fill=black#1] (#2) circle (0.05)}

\begin{document}

\begin{figure} [!htbp]
  \centering
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [smooth,black,tangent=1,tangent pos=0.8] (-1,0) -- coordinate[pos=0.8] (A) (4,0);
    \draw [smooth,blue,thick] (3.85,2.95) to[out=270, in=180] (4.85,1.95);

    \tpointmark{A};
  \end{tikzpicture}
  \qquad
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [smooth,black,tangent=1,tangent pos=0.8] (-1,0) -- coordinate[pos=0.8] (A) (4,0);
    \draw [smooth,blue,thick,tangent=1] (-1,0.5) to[out=-45,in=180] (0,0) to[out=0,in=-135] (1,0.5);

    \tpointmark{A};
  \end{tikzpicture}
\end{figure}

\end{document}

4 Answers 4

10

Welcome! There are two issues: when you set up a tangent coordinate system in another tangent coordinate system, you pick up an additional rotation. Therefore I created the second tangent system in a line that uses the original coordinate system. Further, the in and out angles are absolute, so you you need to add the rotation angle of the current frame.

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\usetikzlibrary{decorations.markings}

\tikzset{
  tangent pos/.style={decoration={markings, mark = at position #1 with {
        \coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
        \coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
        \coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
      }
    },
    postaction=decorate
  },
  %
  tangent/.style={shift=(tangent point-#1), x=(tangent unit vector-#1), y=(tangent orthogonal unit vector-#1)},
}

\newcommand*{\tpointmark}[2][]{\fill [smooth,fill=black#1] (#2) circle (0.05)}

\begin{document}

\begin{figure} [!htbp]
  \centering
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [smooth,black,tangent=1,tangent pos=0.8] (-1,0) -- coordinate[pos=0.8] (A) (4,0);
    \draw [smooth,blue,thick] (3.85,2.95) to[out=270, in=180] (4.85,1.95);

    \tpointmark{A};
  \end{tikzpicture}
  \qquad
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [black,tangent=1] (-1,0) coordinate (A0) -- coordinate[pos=0.8] (A) 
    (4,0) coordinate (A1);
    \path [tangent pos=0.8] (A0) -- (A1);
    \draw [smooth,blue,thick,tangent=1] 
    let \p1=($(1,0)-(0,0)$),
        \n1={atan2(\y1,\x1)} in 
        (-1,0.5) to[out=-45+\n1,in=180+\n1] 
    (0,0) to[out=0+\n1,in=-135+\n1] (1,0.5);
    \tpointmark{A};
  \end{tikzpicture}
\end{figure}
\end{document}

enter image description here

You can avoid this by, instead of setting the unit vectors of the local frame just finding the rotation that brings you there. For the present example this makes things easier, but there are also downsides because if you now say transform shape node texts will be rotated.

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\usetikzlibrary{decorations.markings}

\tikzset{
  tangent pos/.style={decoration={markings, mark = at position #1 with {
        \coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
        \coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
        \coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
      }
    },
    postaction=decorate
  },
  %
  tangent/.style={shift=(tangent point-#1),
  insert path={let \p1=($(tangent unit vector-#1)-(tangent point-#1)$),
  \n1={atan2(\y1,\x1)} in [rotate=\n1]}
   %x=(tangent unit vector-#1), y=(tangent orthogonal unit vector-#1)
   },
}

\newcommand*{\tpointmark}[2][]{\fill [smooth,fill=black#1] (#2) circle (0.05)}

\begin{document}

\begin{figure} [!htbp]
  \centering
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [smooth,black,tangent=1,tangent pos=0.8] (-1,0) -- coordinate[pos=0.8] (A) (4,0);
    \draw [smooth,blue,thick] (3.85,2.95) to[out=270, in=180] (4.85,1.95);

    \tpointmark{A};
  \end{tikzpicture}
  \qquad
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [black,tangent=1,tangent pos=0.8] (-1,0)  -- coordinate[pos=0.8] (A) 
    (4,0);
    \draw [smooth,blue,thick,tangent=1]     (-1,0.5) to[out=-45,in=180] 
        (0,0) to[out=0,in=-135] (1,0.5);
    \tpointmark{A};
  \end{tikzpicture}
\end{figure}
\end{document}

enter image description here

Finally, you do not need an explicit tangent coordinate system at all here. You can just define a pic that is nothing but a wrapper of some code. If you use sloped and transform shape it will also bring you in the tangent space.

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\usetikzlibrary{decorations.markings}

\tikzset{
  tangent pos/.style={decoration={markings, mark = at position #1 with {
        \coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
        \coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
        \coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
      }
    },
    postaction=decorate
  },
  %
  tangent/.style={shift=(tangent point-#1),
  insert path={let \p1=($(tangent unit vector-#1)-(tangent point-#1)$),
  \n1={atan2(\y1,\x1)} in [rotate=\n1]}
   %x=(tangent unit vector-#1), y=(tangent orthogonal unit vector-#1)
   },
  pics/whatever/.style={code={#1}} 
}

\newcommand*{\tpointmark}[2][]{\fill [smooth,fill=black#1] (#2) circle (0.05)}

\begin{document}

\begin{figure} [!htbp]
  \centering
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [smooth,black,tangent=1,tangent pos=0.8] (-1,0) -- coordinate[pos=0.8] (A) (4,0);
    \draw [smooth,blue,thick] (3.85,2.95) to[out=270, in=180] (4.85,1.95);

    \tpointmark{A};
  \end{tikzpicture}
  \qquad
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$Y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$X$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] (3.5,0);
    \draw [black,tangent=1] (-1,0)  -- coordinate[pos=0.8] (A) 
    (4,0) pic[sloped,pos=0.8,transform shape]{whatever={\draw [smooth,blue,thick]   (-1,0.5) to[out=-45,in=180] 
        (0,0) to[out=0,in=-135] (1,0.5);}};

    \tpointmark{A};
  \end{tikzpicture}
\end{figure}
\end{document}

Same result as before.

4
  • Thanks. I upvoted the answer. Just out of curiosity, how can get the angle of the tangent line? Commented May 19, 2020 at 5:37
  • 3
    @RittwikChatterjee It is the \n1 in let \p1=($(1,0)-(0,0)$), \p2=($(tangent unit vector-1)-(tangent point-1)$), \n1={atan2(\y1,\x1)} in. (I just see that the \p2 is not used so I remove it.) After ` \p1=($(1,0)-(0,0)$),` the x and y coordinates of the first basis vector are stored in \x1 and \y1, respectively, so that atan2(\y1,\x1) is the slope angle.
    – user194703
    Commented May 19, 2020 at 5:40
  • Thanks a lot. I wish I could upvote your comment. But I don't have enough reputation. Commented May 19, 2020 at 5:45
  • 2
    @RittwikChatterjee You are welcome!
    – user194703
    Commented May 19, 2020 at 5:49
3

Using the tzplot package:

enter image description here

\documentclass[tikz]{standalone}
    
\usepackage{tzplot}

\begin{document}

\begin{tikzpicture}
\tzhelplines(5,5)
\tzaxes(5,5){$X$}{$Y$}
% red curve: PPC
\tzto[red,thick,out=0,in=90]"curve"(0,4.5)(3.5,0)
% tangent line
\settztangentlayer{main}
\tztangentat"tan"{curve}{1.5}[.5:5]
% dots
\tzvXpointat*{curve}{1.5}(P){$P$}[45]
\tzvXpointat*{tan}{4}(Q){$Q$}[45]
% extract angle between points, saved at \tzangleresult
\tzanglemark[draw=none](P)(Q)(Q-|5,0)
% blue curve: IC
\tztos[blue,thick]($(Q)+(-.7,1)$)
      [out=-75,in=\tzangleresult](Q)
      [out=\tzangleresult-180,in=175]($(Q)+(1,-.3)$);
\end{tikzpicture}

\end{document}
2
  • 2
    I see you're the author of the package. Very useful for microeconomics !
    – JeT
    Commented Mar 13, 2022 at 12:58
  • Thank you. That’s what I wanted!
    – I. Cho
    Commented Mar 15, 2022 at 2:22
2

I have found another way.

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\usetikzlibrary{decorations.markings}

\tikzset{
  tangent pos/.style={decoration={markings, mark = at position #1 with {
        \coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
        \coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
        \coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
      }
    },
    postaction=decorate
  },
  %
  tangent/.style={shift=(tangent point-#1), x=(tangent unit vector-#1), y=(tangent orthogonal unit vector-#1)},
}

\newcommand*{\tpointmark}[2][]{\fill [smooth,fill=black#1] (#2) circle (0.05)}

\begin{document}

\begin{figure} [!htbp]
  \centering
  \begin{tikzpicture} [font=\footnotesize]
    \draw [thick,<->] (0,5) node[above]{$y$} -- (0,0) node[below left]{$0$} coordinate (axis1) -- (5,0) node[right]{$x$};

    \draw [smooth,red,thick,tangent pos=0.3] (0,4.5) to[out=0, in=90] coordinate[pos=0.3] (E) (3.5,0);

    \draw [black,tangent=1] (-1,0) coordinate (T1) -- coordinate[pos=0.8] (A) (4,0) coordinate (T2);
    % Below we calculate the angle of the tangent
    \pgfmathanglebetweenpoints{\pgfpointanchor{T1}{center}}{\pgfpointanchor{T2}{center}};
    \begin{scope} [shift={(A)}, rotate around={\pgfmathresult:(A)}]
      % Now we are in the coordinate system whose origin is (A)
      % and slope of the x-axis is the slope of the tangent.
      \draw [smooth,blue,thick] (-1,0.5) to[out=-45,in=180] (0,0) to[out=0,in=-135] (1,0.5);
    \end{scope}

    \tpointmark{E};
    \tpointmark{A};
  \end{tikzpicture}
\end{figure}

\end{document}

1

The usual TikZ way for drawing tangents is using decorations.markings, that is, tangents as decorations.

This (plain) Asymptote way is for comparison. For Asymptote, tangent/normal operations are built-in, thus it make me mathematically comfortable in drawing such figures.

Given pathP and a real number t- relative position, we can take a point P on that path with pair P=relpoint(pathP,t); and take the incoming tangent at P with pair Pt=dir(pathP,t);. Now we can get the tangent segment like this P-2Pt--P+4Pt.

Next we can take a point Q on the tangent segment. From Q we control 2 paths, pathQleft and path Qright, starting from Q in tangent direction (no need to calculate angle, slope). That's the simplicity of the figure!

enter image description here

unitsize(1cm);
import math;   // for grid
add(grid(5,5,lightgray));
path pathP=(0,4.5) {right}..(3.5,0){down};
real t=.3;
pair P=relpoint(pathP,t);
pair Pt=dir(pathP,t);
draw(pathP,deepcyan);
draw(P-2Pt--P+4Pt,red);
pair Q=P+2.5Pt;
path pathQright=Q .. controls Q+Pt and  Q+(2,.5)+dir(-130) .. Q+(2,.5);
path pathQleft=Q .. controls Q-Pt and  Q+(-1,2)+dir(-70) .. Q+(-1,2);

draw(pathQright^^pathQleft,blue);
dot("$P$",align=NE,P,deepcyan);
dot("$Q$",align=SW,Q,blue);

draw(Label("$x$",EndPoint,align=SE),(0,0)--(5.5,0),Arrow(TeXHead));
draw(Label("$y$",EndPoint,align=W),(0,0)--(0,5.5),Arrow(TeXHead));
shipout(bbox(5mm,invisible));

You must log in to answer this question.

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