2

Using TiKZ, I want to plot a cubic curve, with a double point.  I tried just doing that with this program and got this gap on the left hand edge of the result.

\documentclass{article}
    \usepackage{pgfplots}
    \pgfplotsset{tick style={draw=none}}

\begin{document}

\begin{tikzpicture} \begin{axis}[ xmin=-3, xmax=3, xticklabels={}, ymin=-3, ymax=3, yticklabels={}, axis lines=middle, domain=-3:3, samples=250, smooth, % use same unit vectors on the axis axis equal image=true, ] \addplot [thick] {sqrt(x^3-3x+2) }; \addplot [thick] {-sqrt(x^3-3x+2) };

    \end{axis}; 
\end{tikzpicture} 


\end{document}

Cubic curve with a gap

I believe TiKZ has trouble plotting the square root of x^3-3*x+2 very close to where the tangent is vertical at x=-2.  I can add a short vertical line by hand, to fill in the gap.  But it does not look good.  Is there a more direct way to get TiKZ to plot that square root all the way down to 0?

  • 2
    Try samples=301. Alternatively, you could do another plot on top over a smaller domain. For instance if you also include \addplot [thick, domain=-3:0] {sqrt(x^3-3*x+2) }; and \addplot [thick, domain=-3:0] {-sqrt(x^3-3*x+2) }; you get the desired plot. This is hackish, but the problem comes down to sampling at the correct points. Or, better still use a parameterized plot. – Peter Grill Jan 08 '21 at 18:52
  • 1
    Since x^3-3*x+2=(x-1)^2*(x+2), we see that y=(+/-)sqrt(x^3-3*x+2) is essentially just y=(+/-)(x-1)*sqrt(x+2). This means that there is no reason to have domain=-3:0. Instead, domain=-2:0 should be enough. – Ruixi Zhang Jan 08 '21 at 19:41
  • @RuixiZhang Thanks. This is one of a series and most do not have simple factorization, so Peter Grill's suggestion works better for me. – Colin McLarty Jan 08 '21 at 23:19
  • @PeterGrill The extra \addplot suggestion works perfectly. This is very valuable knowledge though it is easy to see in hindsight: segmenting the plot can cause better sampling. – Colin McLarty Jan 08 '21 at 23:21
  • @PeterGrill Three people have given me good information, but your comment is the most helpful to me and will generalize the best to other people with a similar issue, so I would like to accept it as answer. Will you make it an answer? – Colin McLarty Jan 09 '21 at 20:09
  • @ColinMcLarty: Posted answer as requested – Peter Grill Jan 10 '21 at 17:55

3 Answers3

3

For fun: it runs nicely with pstricks:

\documentclass[11pt,svgnames, border=3pt]{standalone}
\usepackage{pst-func}
\begin{document}

\begin{pspicture}(-2.9,-2.9)(3,3) \psaxes[ticksize=2pt, labelFontSize=\scriptstyle color{SteelBlue},% showorigin=false, arrows=->,arrowinset=0.12, linecolor=SteelBlue]% (0,0)(-2.95,-2.9)(3,3)[$x$, -120][$y$,-135] \uputdl{$ O $} \psset{linewidth=1pt,linecolor=IndianRed,algebraic, plotpoints=500} \psplot{-2}{3}{sqrt(x^3-3x + 2)} \psplot{-2}{3}{-sqrt(x^3-3x + 2)} \end{pspicture}

\end{document}

enter image description here

Bernard
  • 271,350
2

Your "problem" was that you didn't show the axis tick labels when plotting. If you would have done this, you would have noticed that the lower bound is -2 and thus giving a lower domain value of -3 doesn't make really sense. So just changing this to -2 is enough to solve your problem. Then you can play with the number of samples to get the proper "smoothness".

But you could also use non-linear spacing to plot that function with the default number of samples being 25 to get an almost identical result, especially when you use the factorized version of that function that already was stated by Ruixi Zhang in the comment below the question.

If you think that is not good enough you could play with the "non-linearity factor" a or with the number of samples.

Hopefully this and the comments in the code are enough so you understand what's going on.

% used PGFPlots v1.17
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usepgfplotslibrary{colorbrewer}
    \pgfplotsset{
        % use this `compat` level or higher to make use of Lua computation engine
        compat=1.12,
        % (only used for proper displaying. The `cycle list` is from the `colorbrewer` library)
        cycle list/Dark2,
        cycle multiindex* list={
            [1 of]mark list\nextlist
            Dark2\nextlist
        },
    }
\begin{document}
\begin{tikzpicture}[
    % declare functions
    declare function={
        % function to plot
%        f(\x) = sqrt(\x^3 - 3*\x + 2);
        % can be rewritten (as stated by Ruixi Zhang) as
        f(\x) = (\x-1)*sqrt(\x+2);
        % state lower and upper boundaries
        lb = -2;
        ub = 3;
        % -----------------------------------------------------------------
        %%% non-linear spacing:
        %%% adapted from <https://tex.stackexchange.com/a/443731/95441>
        % "non-linearity factor"
        a = 1;
        % function to use for the nonlinear spacing
        Y(\x) = exp(a*\x);
        % rescale to former limits
        X(\x) = (Y(\x) - Y(lb))/(Y(ub) - Y(lb)) * (ub - lb) + lb;
    },
]
    % -------------------------------------------------------------------------
    \begin{axis}[
        xmin=-3,
        xmax=3,
        ymin=-3,
        ymax=3,
        axis lines=middle,
        smooth,
        axis equal image=true,
        % adjusted to proper limits
        % (as variables given above)
        domain=lb:ub,
        mark size=1pt,
    ]
        % ("usual" attempt only corrected for the lower domain bound)
        \addplot+ [samples=201,no markers,thick] { sqrt(\x^3 - 3*\x + 2)};
        \addplot+ [samples=201,no markers,thick] {-sqrt(\x^3 - 3*\x + 2)};
    % here plotting with 25 points with non-linear spacing
    \addplot+ ({X(x)}, { f(X(x))});

% \addplot+ [no markers]({X(x)}, {-f(X(x))}); \end{axis}; \end{tikzpicture} \end{document}

image showing the result of above code

Stefan Pinnow
  • 29,535
  • Thanks. Several things I can think about, especially the non-linearity factor. One question: It seems like setting the lower bound of the range equal to the x-intercept of the curve only works when it is exact. Is that right? For examples where the x-intercept is irrational, when I try a lower bound that approximates it to two decimal places, I still get the gap. – Colin McLarty Jan 08 '21 at 23:39
  • 1
    I am not 100% sure I get your question right. domain gives the range were the function should be plotted and samples gives the number of points were the function is evaluated (in the domain). In this case there is no solution for x-values <−2. So the plotting can only start with the first calculated value being ≥−2. To easily visualize that, take the code from the question, replace \addplot with \addplot+ and then decrease the number of samples. Then the gap will get bigger and bigger. – Stefan Pinnow Jan 09 '21 at 05:55
  • Pinow. Yes, and that works to eliminate the gap when the lowest x-value is -2. But I cannot make anything like it work when the lowest is, say minus the cube root of 2. I can only get it it to eliminate the gap when the lowest actual value of x can be exactly specified as the lower bound on the range. – Colin McLarty Jan 09 '21 at 14:19
  • First, not the first point, but some point needs to be a valid as close as possible point. Second, I don't see the problem. You don't need to specify the number directly to lb. You can also place an expression there. In this example you could replace the line lb = -2; with lb = -1 * sqrt(4); which would also work ... – Stefan Pinnow Jan 09 '21 at 15:32
  • Thanks, I understand what you are saying. But I need this to work for other examples too, and I cannot get it to. So far as I know, I cannot replace the line lb=-2 by the line 'lb' = lowest root of x^3-4x+4=-2. And when I give a digital approximation to that root, good to two decimal places, it still leaves the gap in the curve. – Colin McLarty Jan 09 '21 at 19:32
  • If you really mean x^3-4x+4=-2 and not sqrt(...) then here is no problem because the domain is from −∞ to ∞ ... – Stefan Pinnow Jan 09 '21 at 19:52
  • I think the original question is fully answered. If you agree please consider upvoting my answer (with the upward pointing arrow to the left of it and accepting it (by clicking on the checkmark ✓). If you have a new/another question feel free to ask a follow-up question. – Stefan Pinnow Jan 09 '21 at 19:56
  • The lowest root of a polynomial is identical to the lowest zero of its square root. – Colin McLarty Jan 09 '21 at 19:57
1

Changing the domain as per another answer is the corect thing to do in this case. However, I have expereienced cases like this and the following has usually worked for me:

  1. Adjust the samples= setting. In this particular case samples=301 works.

  2. Do a separate plot just over the problem region to fill in the missing potion. In this particular case including the following two lines seems to work

    \addplot [thick, domain=-3:0] {sqrt(x^3-3*x+2) }; 
    \addplot [thick, domain=-3:0] {-sqrt(x^3-3*x+2)};
    
Peter Grill
  • 223,288