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.
You could also plot the tangents, like eg this:
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.
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.
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
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.
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).
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)-xfp(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