Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plotting a line tangent to a function at a point

Tags:

julia

Heres a block of code that plots a function over a range, as well as the at a single input :

a = 1.0
f(x::Float64) = -x^2 - a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])

enter image description here

i would like to plot the line, tangent to the point, like so:

enter image description here

Is there a pattern or simple tool for doing so?

like image 347
neutrino Avatar asked Feb 17 '21 06:02

neutrino


People also ask

How do you graph a tangent line at a point?

1) Find the first derivative of f(x). 2) Plug x value of the indicated point into f '(x) to find the slope at x. 3) Plug x value into f(x) to find the y coordinate of the tangent point. 4) Combine the slope from step 2 and point from step 3 using the point-slope formula to find the equation for the tangent line.

Can you draw a tangent line at an endpoint?

In general, we can't draw tangent lines at parts of a graph that look like "points" or "corners": We also can't draw tangent lines at places where the function doesn't exist.

Can you have a tangent to a point?

A tangent is a line that approximates the curve near the point - such that if you zoom in close enough on the point, the tangent and curve become pratically indistinguishable.


2 Answers

That depends on what you mean by "pattern or simple tool" - the easiest way is to just derive the derivative by hand and then plot that as a function:

hand_gradient(x) = -2x

and then add plot!(hand_gradient, 0:0.01:3) to your plot.

Of course that can be a bit tedious with more complicated functions or when you want to plot lots of gradients, so another way would be to utilise Julia's excellent automatic differentiation capabilities. Comparing all the different options is a bit beyond the scope of this answer, but check out https://juliadiff.org/ if you're interested. Here, I will be using the widely used Zygote library:

julia> using Plots, Zygote

julia> a = 1.0;

julia> f(x) = -x^2 - a;

[NB I have slightly amended your f definition to be in line with the plot you posted, which is an inverted parabola]

note that here I am not restricting the type of input argument x to f - this is crucial for automatic differentiation to work, as it is implemented by runnning a different number type (a Dual) through your function. In general, restricting argument types in this way is an anti-pattern in Julia - it does not help performance, but makes your code less interoperable with other parts of the ecosystem, as you can see here if you try to automatically differentiate through f(x::Float64).

Now let's use Zygote to provide gradients for us:

julia> f'
#43 (generic function with 1 method)

as you can see, running f' now returns an anonymous function - this is the derivative of f, as you can verify by evaluating it at a specific point:

julia> f'(2)
-4.0

Now all we need to do is leverage this to construct a function that itself returns a function which traces out the line of the gradient:

julia> gradient_line(f, x₀) = (x -> f(x₀) + f'(x₀)*(x-x₀))
gradient_line (generic function with 1 method)

this function takes in a function f and a point x₀ for which we want to get the tangent, and then returns an anonymous function which returns the value of the tangent at each value of x. Putting this to use:

julia> default(markerstrokecolor = "white", linewidth = 2);

julia> scatter(f, -3:0.1:3, label = "f(x) = -x² - 1", xlabel = "x", ylabel = "f(x)");

julia> scatter!([1], [f(1)], label = "", markersize = 10);

julia> plot!(gradient_line(f, 1), 0:0.1:3, label = "f'(1)", color = 2);

julia> scatter!([-2], [f(-2)], label = "", markersize = 10, color = 3);

julia> plot!(gradient_line(f, -2), -3:0.1:0, label = "f'(-2)", color = 3)

enter image description here

like image 133
Nils Gudat Avatar answered Oct 03 '22 23:10

Nils Gudat


Well, the tool is called high school math :)

You can simply calculate the slope (m) and intersect (b) of the tanget (mx + b) and then plot it. To determine the former, we need to compute the derivative of the function f in the point a, i.e. f'(a). The simplest possible estimator is the difference quotient (I assume that it would be cheating to just derive the parabola analytically):

m = (f(a+Δ) - f(a))/Δ

Having the slope, our tanget should better go through the point (a, f(a)). Hence we have to choose b accordingly as:

b = f(a) - m*a

Choosing a suitably small value for Δ, e.g. Δ = 0.01 we obtain:

Δ = 0.01
m = (f(a+Δ) - f(a))/Δ
b = f(a) - m*a

scatter(f, -3:.1:3)
scatter!([a], [f(a)])
plot!(x -> m*x + b, 0, 3)

plotwithtangent

Higher order estimators for the derivative can be found in FiniteDifferences.jl and FiniteDiff.jl for example. Alternatively, you could use automatic differentiation (AD) tools such as ForwardDiff.jl to obtain the local derivative (see Nils answer for an example).

like image 34
carstenbauer Avatar answered Oct 04 '22 00:10

carstenbauer