5

I use to draw function curves with Bezier, when I want them to fit multiple conditions, i.e. tangent lines, maximum and minimum, and the curve going through chosen points. This is to be used with my students when working on functions properties.
I assumed that I could do this more easily with hobby library, but I can't get to something even acceptable, so I need your help.
Here are the intended curve (in orange) and the result with Hobby (in dashed purple).
Hobby ugly curve

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{hobby}
\usetikzlibrary{arrows.meta}

\begin{document}

\begin{tikzpicture}[use Hobby shortcut]
    \tikzset{tangent/.style={in angle ={(180+#1)},
            Hobby finish,
            designated Hobby path=next,
            out angle=#1}}
    \tikzset{axe/.style={line width=1pt,-{Latex[length=4mm,width=2mm]}}}
    \tikzset{courbe/.style={line width=1.5pt,dashed, purple}}
    \draw[cyan,very thin] (-7,-4) grid (6,4);
    \draw[axe] (-7,0) -- (6,0);
    \draw[axe] (0,-4) -- (0,4);

    % Bezier curve
    
        % points
    \coordinate (p1) at (-7,-4);
    \coordinate (p2) at (-5,0);
    \coordinate (p3) at (-3,2);
    \coordinate (p4) at (0,-3);
    \coordinate (p5) at (1,-1);
    \coordinate (p6) at (2,-4);
    \coordinate (p7) at (4,.5);
    \coordinate (p8) at (6,3);
    
        % control points
    \coordinate (b1) at (-6,-3.5);
    \coordinate (a2) at (-6.5,0);
    \coordinate (b2) at (-4,0); 
    \coordinate (a3) at (-4,2);
    \coordinate (b3) at (-1.9,2);
    \coordinate (a4) at (-0.4,-3);
    \coordinate (b4) at (.5,-3);
    \coordinate (a5) at (0.5,-1);
    \coordinate (b5) at (1.5,-1);
    \coordinate (a6) at (1.5,-4);
    \coordinate (b6) at (2.5,-4);
    \coordinate (a7) at (3,0.5);
    \coordinate (b7) at (4.5,.5);
    \coordinate (a8) at (5.5,1);

        % curve 
    \draw[line width=1.5pt, orange]
        (p1) .. controls (b1) and (a2) .. (p2)
        (p2) .. controls (b2) and (a3) .. (p3)
        (p3) .. controls (b3) and (a4) .. (p4)
        (p4) .. controls (b4) and (a5) .. (p5)
        (p5) .. controls (b5) and (a6) .. (p6)      
        (p6) .. controls (b6) and (a7) .. (p7)  
        (p7) .. controls (b7) and (a8) .. (p8)      
        ;   
        
    % Hobby curve
    
    \draw[courbe] 
        ([tangent=25]-7,-4) ..
        ([tangent=0]-5,0) ..
        ([tangent=0]-3,2) ..
        ([tangent=0]0,-3) ..
        ([tangent=0]1,-1) ..
        ([tangent=0]2,-4) ..
        ([tangent=0]4,.5) ..
        ([tangent=75]6,3);
    
\end{tikzpicture}

\end{document}

I tried to add some tension with [tension=0.5] for example, and even other properties but can't see where it leads.

3
  • 3
    The constraint of making a curve that is suitable for a function doesn't fit well with Hobby's algorithm as the optimisation in the algorithm doesn't have preferred directions so will happily make a curve seemingly double back on itself. I've often wondered if there's a modification that would work for this sort of situation but I've not come up with anything as yet. So I would not recommend using hobby for this. – Andrew Stacey Jan 30 at 19:56
  • 2
    Yeah what @AndrewStacey said. But, if you want a work around just specify more points around the points where the curve is not behaving as desired. That is, increase the density of the given points near the points of any local max and min. With this I have been able to achived the desired results and let hobby do the rest. – Peter Grill Jan 30 at 19:58
  • Thanks to you both. I don't find it relevant to add too much points, since I'm looking for an easier method. I'll stick with my well known Bezier curve, then. – SebGlav Jan 30 at 20:44
4

Since you mainly specify the local extrema, you can work with the to syntax and

\draw[in=180,out=0] .... ;

You can still specify the slopes at specific points by locally adjusting the in and out keys. You only need to make sure that a given in value and the subsequent out value differ by 180. Additional fine tuning can be achieved by playing with the looseness, or even out looseness and in looseness. They indicate how far the control points are away from the first and last point of the sequence, while the in and out keys set the angles of these control points. The result of my very first attempt is the cyan-blue curve.

enter image description here

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{hobby}
\usetikzlibrary{arrows.meta}

\begin{document}

\begin{tikzpicture}[use Hobby shortcut]
    \tikzset{tangent/.style={in angle ={(180+#1)},
            Hobby finish,
            designated Hobby path=next,
            out angle=#1}}
    \tikzset{axe/.style={line width=1pt,-{Latex[length=4mm,width=2mm]}}}
    \tikzset{courbe/.style={line width=1.5pt,dashed, purple}}
    \draw[cyan,very thin] (-7,-4) grid (6,4);
    \draw[axe] (-7,0) -- (6,0);
    \draw[axe] (0,-4) -- (0,4);

    % Bezier curve
    
        % points
    \coordinate (p1) at (-7,-4);
    \coordinate (p2) at (-5,0);
    \coordinate (p3) at (-3,2);
    \coordinate (p4) at (0,-3);
    \coordinate (p5) at (1,-1);
    \coordinate (p6) at (2,-4);
    \coordinate (p7) at (4,.5);
    \coordinate (p8) at (6,3);
    
        % control points
    \coordinate (b1) at (-6,-3.5);
    \coordinate (a2) at (-6.5,0);
    \coordinate (b2) at (-4,0); 
    \coordinate (a3) at (-4,2);
    \coordinate (b3) at (-1.9,2);
    \coordinate (a4) at (-0.4,-3);
    \coordinate (b4) at (.5,-3);
    \coordinate (a5) at (0.5,-1);
    \coordinate (b5) at (1.5,-1);
    \coordinate (a6) at (1.5,-4);
    \coordinate (b6) at (2.5,-4);
    \coordinate (a7) at (3,0.5);
    \coordinate (b7) at (4.5,.5);
    \coordinate (a8) at (5.5,1);

        % curve 
    \draw[line width=1.5pt, orange]
        (p1) .. controls (b1) and (a2) .. (p2)
        (p2) .. controls (b2) and (a3) .. (p3)
        (p3) .. controls (b3) and (a4) .. (p4)
        (p4) .. controls (b4) and (a5) .. (p5)
        (p5) .. controls (b5) and (a6) .. (p6)      
        (p6) .. controls (b6) and (a7) .. (p7)  
        (p7) .. controls (b7) and (a8) .. (p8)      
        ;   
        
    % Hobby curve
    
    \draw[courbe] 
        ([tangent=25]-7,-4) ..
        ([tangent=0]-5,0) ..
        ([tangent=0]-3,2) ..
        ([tangent=0]0,-3) ..
        ([tangent=0]1,-1) ..
        ([tangent=0]2,-4) ..
        ([tangent=0]4,.5) ..
        ([tangent=75]6,3);

  \draw[blue,double=cyan,thick,in=180,out=0,looseness=0.6] 
        (-7,-4) to[out=25]
        (-5,0) to
        (-3,2) to
        (0,-3) to
        (1,-1) to
        (2,-4) to
        (4,.5) to[in=180+75]
        (6,3);
    
\end{tikzpicture}
\end{document}
2
  • Thanks a lot, @Pumuckl. That's a pretty interesting solution to avoid all the control points in this case, even if it's not using the Hobby algorithm. – SebGlav Jan 31 at 9:29
  • 1
    @SebGlav Yes, I do not know how to achieve this with the Hobby algorithm, but according to the above comments it may not be trivial (or even feasible). Yet I'd definitely be interested in seeing how this works. – user234180 Jan 31 at 18:21

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.