Suppose that a curve is given as the graph of a function,

*y = f(x)*. We have that the slope in the point

*(a, f(a))*is equal to its derivative in

*a*

and the equation of the tangent line can be stated as follows

With this in mind we can write a snippet of code which visualize the tangent of a curve:

from numpy import sin,linspace,power from pylab import plot,show def f(x): # sample function return x*sin(power(x,2)) # evaluation of the function x = linspace(-2,4,150) y = f(x) a = 1.4 h = 0.1 fprime = (f(a+h)-f(a))/h # derivative tan = f(a)+fprime*(x-a) # tangent # plot of the function and the tangent plot(x,y,'b',a,f(a),'om',x,tan,'--r') show()The result is as follows:

The f is plotted with a blue curve and the tangent is the dashed line. Looking at the graph it is actually easy to observe that the tangent gives us a way to visualize the slope of a curve in a point. Let's see how this can help us in a practical example. Consider the fresh potatoes consumer price index between the years 1949 and 2006:

from numpy import arange # Fresh potatoes: Annual Consumer price index, 1949-2006 # obatined at https://explore.data.gov/Agriculture/U-S-Potato-Statistics/cgk7-6ccj price_index = [21.0,17.6,19.3,28.9,21.1,20.5,22.1,26.4,22.3,24.4, 24.6,28.0,24.7,24.9,25.7,31.6,39.1,31.3,31.3,32.1,34.4,38.0,36.7, 39.6,58.8,71.8,57.7,62.6,63.8,66.3,63.6,81.0,109.5,92.7,91.3,116.0, 101.5,96.1,116.0,119.1,153.5,162.6,144.6,141.5,154.6,174.3,174.7, 180.6,174.1,185.2,193.1,196.3,202.3,238.6,228.1,231.1,247.7,273.1] t = np.arange(1949,2007)From the calculus we have that the derivative is positive when f is increasing, it is negative when f is decreasing and zero when f has a saddle point. So, if we look at the tangent of the curve of the consumer price index in a certain year we have that it has a positive slope when the price index is increasing, a negative slope when the price are decreasing and it is constant when the trend is going to change. Using an interpolation of the data we loaded above we can plot the tangent in each year we want:

from scipy import interpolate def draw_tangent(x,y,a): # interpolate the data with a spline spl = interpolate.splrep(x,y) small_t = arange(a-5,a+5) fa = interpolate.splev(a,spl,der=0) # f(a) fprime = interpolate.splev(a,spl,der=1) # f'(a) tan = fa+fprime*(small_t-a) # tangent plot(a,fa,'om',small_t,tan,'--r') draw_tangent(t,price_index,1991) draw_tangent(t,price_index,1998) plot(t,price_index,alpha=0.5) show()

The graph shows the data contained in the array price_index and shows the tangent of the curve for the years 1991 and 1998. Using the tangent, this graph gives an emphasis about the fact that the price index is decreasing during the years around 1991 and increasing around 1998.

Find out more about derivative approximation in the post Finite differences with Toeplitz matrix.

Should interpolate.splrep(t,price_index) be interpolate.splrep(t,y)?

ReplyDeleteyup!

DeleteThe code presented here in pypedia:

ReplyDelete* http://bit.ly/ZqgFgy

* http://bit.ly/10eRS24

press "Run"

This comment has been removed by the author.

ReplyDeleteHere's the same graph made with plotly's Python sandbox: https://plot.ly/~jackp/506

ReplyDeleteMore examples of graphs made with Python in plotly: https://plot.ly/gallery

Thanks James, it looks so nice.

DeleteThis comment has been removed by the author.

ReplyDeleteHi was wondering if there is a way of getting the gradient of the tangent once the tangent has been plotted

ReplyDeleteHi Abu, the gradient of the tangent is a scalar value which represents its slope. Just plotting the tangent should give a good idea of it's slope.

DeleteThank you for the quick reply what I wanted to ask is can fprime be taken as the gradient of the tangent?

Deleteyes, fprime is the slope of the tangent.

DeleteVery nice. I have a question:

ReplyDelete* How would you draw a straight line tangent in semilog coordinates?

hi bogdan, you have to workout the equation of the tangent differently. This can help: https://www.graphpad.com/guides/prism/7/curve-fitting/reg_fitting_lines_to_semilog.htm

DeleteThanks, unfortunately my case is not that simple. I know how to do it when Y is log and you have just that line. However, let use your example where your have your example with function being interpolated and get the tangent. I used the simple line not the 10^ and draws pretty good but it is slightly curved. with 10^ it gives overflow. Could your try your example with semilogY and draw the tangent in such conditions. Basically I have the discrete function already drawn and I want to draw a tangent in one point.

Deletehi again Bogdan, I'm afraid that I can't try that at the moment. However, if you have an overflow problem, you can try scaling your data linearly first then apply the 10^. Of course, you'll have to fix the ticks on the axis then.

DeleteIn any case, I'm not sure that what you are trying to do is sound. A line in a linear scale is not a line in semilog. A modified curve to look like a line will not highlight the trend.

I am just trying to do something similar to yours but in semilogY coordinates. If you try your example in such coordinates you will understand the problem. It is an easy change in your code. It is not a scaling problem is a problem of calculating the slope in such coordinates if your original graph is already in semilogY coordinates and I cannot change that order.

DeleteHi JustGlowing, I can see that my last message has not been approved. Basically I wanted just a simple change in your tangent example: draw the tangent in semilogy coordinates. I am doing it OK, but my impression is that the tangent is a little curved. I was curios to see how you do it and if your tangent would be a perfectly straight line.

ReplyDeleteHi there, all your comments are approved. I might try to do your experiment, but don't expect much as I'm super busy lately.

Deletehi! I was wondering if it's possible to draw a tangent line on a given graph? So basically is there a way to plot a tangent line without knowing the function of the original graph?

ReplyDeletehi there, the second example in this post shows exactly that.

Delete