How to plot Newton's method

I’m looking at how to plot Newton’s method. I was going to add x values of each itteration, with y=0 to a DataFrame, then run a scatter plot. Is this what I should do, or is there a better way to go about this?

Probably you just need a vector of data. A DataFrame is a unnecessary complication.

6 Likes

You could also plot the tangents, like eg this:

3 Likes

Plotting \log(\| F(x_n) \|) vs n should tell you what you want to know. Semilog plots are the standard way to do this so you can see what is happening in the terminal phase of the iteration.

If you have a scalar equation and want to plot f(x_n) vs x_n, a semilog plot is still the way to go. If you want to plot x_n vs n, a scatter plot makes sense. You can plot your results with the graph of f(x) as an overlay. This is not as fancy was the moving graph that @Tamas_Papp points to, but is easy to do.

As @lmiq says, a DataFrame is overkill for this.

1 Like

That’s what I wanted, I’ll go over how to do this. I always forget the formula for a tangent.

(f(x)-b)/f'(x)=x

then I can’t remember how to find b.

That’s interesting. I’m not familiar with semilog plots, and I’m learning linear algebra, so I’m not sure how to write that as code.

As for data frames, I don’t think it’s an issue, but in Maple it creates a crazy large file, so I see where it’s not the best option.

Is a vector a csv? I don’t know how to do data in a matrix.

No, a vector is just a list of numbers. You can crate one with (assuming you are storing numbers):

x = Float64[]

And then add data to it with, for instance,

push!(x,1.2321)

The resulting x is what you need to plot something.

thanks.

1 Like

This could be improved, but Makie offers a nice way to explore Newton’s method and its dependence on the initial value. If you install enough packages to get this to run, dragging the initial points shows the method pretty clearly.

using AbstractPlotting
using AbstractPlotting.MakieLayout
using GLMakie

using ForwardDiff
D(f) = x -> ForwardDiff.derivative(f, float(x))


function newton(f=x->x^5 - x - 1, x0=1, a=-1, b=1.5, n = 20)

    function add_move!(scene, points, pplot)
        idx = Ref(0); dragstart = Ref(false); startpos = Base.RefValue(Point2f0(0))
        on(events(scene).mousedrag) do drag
            if ispressed(scene, Mouse.left)
                if drag == Mouse.down
                    plot, _idx = mouse_selection(scene)
                    if plot == pplot
                        idx[] = _idx; dragstart[] = true
                        startpos[] = to_world(scene, Point2f0(scene.events.mouseposition[]))
                    end
                elseif drag == Mouse.pressed && dragstart[] && checkbounds(Bool, points[], idx[])
                    pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
                    
                    # we work with components, not vector
                    x,y = pos
                    
                    ptidx = idx[]
                    
                    x = clamp(x, a, b)
                    y = zero(y)
                    points[][idx[]] = [x,y]
                    
                    points[] = points[]
                end
            else
                dragstart[] = false
            end
            return
        end
    end

    start_point = Node(Point2f0[(x0, 0)])
    points = lift(start_point) do x₀
        xs = [x₀[1][1]]
        for i in 1:n
            xᵢ₋₁ = xs[end]
            xᵢ = xᵢ₋₁ - f(xᵢ₋₁) /D(f)(xᵢ₋₁)
            push!(xs, xᵢ)
        end
        xs
    end

    plt_points = lift(points) do pts
        xs = Float64[]
        ys = Float64[]
        for i in 1:length(pts)-1
            pᵢ, pᵢ₊₁ = pts[i], pts[i+1]
            append!(xs, [pᵢ, pᵢ, pᵢ₊₁])
            append!(ys, [0, f(pᵢ), 0])
        end
        (xs, ys)
    end

    scene = Scene()
    lines!(scene, a..b, f, linewidth=5, color=:blue)
    lines!(scene, a..b, zero, color=:red)
    lines!(scene, plt_points, color=:black, linewidth=2)
    scatter!(scene, start_point, color=:red)

    add_move!(scene, start_point, scene[end])

    scene
end
1 Like

I ran it. I get warnings from packages but no errors. Is it supposed to output a plot?

Try: newton()

scatter! not defined.

It might be missing a package, or that could be a syntax error.

That’s from AbstractPlotting, or should be.

Ok, I’m using Jupyter, does it matter if the using commands are in the same code chunk as other code?

I get the scatter not defined error when I run

Try:newton()

I only ran from a terminal. I’m not sure, but WGLMakie might work in place of GLMakie.

1 Like

For an x, given f(x) and f'(x), if you want the tangent as y = a + bx, then just match values and derivatives, ie f(x) = a + bx and f'(x) = b, obtaining a = f(x) - x f'(x).

5 Likes

using Plots
using ForwardDiff
f(x)=((x)^6)-2
fp(x)= ForwardDiff.derivative(f, x)
t(x)=-1*(f(x)-xfp(x)+fp(x))
P1=plot(f,1:.001:1.55,legend=false);hline!([0])
for i in 1:9
root=x
x=BigFloat(x)-BigFloat(f(x)/fp(x))
e=BigFloat(abs((x)-(root)))
push!(df,(x,e,f(x)))
t(x)=-(f(root)-x
fp(root)+fp(root))
plot!(t,1:.001:1.55)
vline!([root])
end

this gives me lines with the correct slope, but they don't move with root or x, to be tangents.

Okay, this should work in Jupyter. The @manipulate macro from SimplePlots allows the interaction with the initial point.

using Plots, Interact
using ForwardDiff
D(f) = x -> ForwardDiff.derivative(f, float(x))
f(x)  = x^5 - x - 1
a, b = -1.5, 1.5
nsteps = 20
@manipulate for x0=slider(a:0.1:b, value=1.0, label="x0")
    ts = range(a, b, length=251)
    plot(ts, f.(ts), xlim=(a,b), ylim=(-5,5), legend=false)
    plot!(ts, 0 .* ts) 
    scatter!([x0],[0])

    xs = Float64[]
    ys = Float64[]
    for i in 1:nsteps
        x1 = x0 - f(x0)/D(f)(x0)
        append!(xs, [x0, x0, x1])
        append!(ys, [0,f(x0), 0])
        x0 = x1
    end

    plot!(xs, ys)

end

[Edited to use Plots+Interact]

I,m getting slider not defined

UndefVarError: slider not defined

Stacktrace:
 [1] top-level scope at C:\Users\Brett\.julia\packages\SimplePlots\6y94O\src\interact\gui.jl:39
 [2] include_string(::Function, ::Module, ::String, ::String) at .\loading.jl:1091