Monday, February 18, 2013

Visualizing the tangent

The tangent to a curve is the straight line that touches the curve at a given point. One reason that tangents are so important is that they give the slopes of straight lines. So, if your curve represents a time series you can tell the ratio of change of your values just looking at the tangent.
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.

18 comments:

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

    ReplyDelete
  2. This comment has been removed by the author.

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

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

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hi was wondering if there is a way of getting the gradient of the tangent once the tangent has been plotted

    ReplyDelete
    Replies
    1. Hi 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.

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

      Delete
    3. yes, fprime is the slope of the tangent.

      Delete
  6. Very nice. I have a question:

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

    ReplyDelete
    Replies
    1. 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

      Delete
    2. Thanks, 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.

      Delete
    3. hi 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.

      In 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.

      Delete
    4. 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.

      Delete
  7. Hi 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.

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

      Delete