8

Suppose I have two curves intersect at some point, how can I read the coordinates from the graph, not read by eye, but find it with more precision by computer.

For example, here are two lists created by simple functions just for illustration. However, the true list is not created by simple functions. So, using FindRoot is not welcomed. Also, do not assume the points is very dense, so that you can just find the coordinates from the two list with the shortest length. For the sparse points, the coordinates got in that way will have a large error.

For your convenience, you can start with the following code:

lst1 = Table[{x, x^2}, {x, 0, 5, 0.5}];
lst2 = Table[{x, x + 3}, {x, 0, 5, 0.5}];
GraphicsRow[{ListLinePlot[{lst1, lst2}], ListPlot[{lst1, lst2}]}]

enter image description here

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
an offer can't refuse
  • 1,745
  • 12
  • 23

3 Answers3

12

The internal function Graphics`Mesh`FindIntersections has limitations that are not well understood, but it can be applied directly to plots. For normal plots, it has always worked for me. It will find all the intersections, too, if there are more than one.

lst1 = Table[{x, x^2}, {x, 0, 5, 0.5}];
lst2 = Table[{x, x + 3}, {x, 0, 5, 0.5}];
plot = ListLinePlot[{lst1, lst2}]

Graphics`Mesh`FindIntersections@plot
(*  {{2.28571, 5.28571}}  *)

To compare with the OP's answer using Interpolation, this method is equivalent to using InterpolationOrder -> 1.

f = Interpolation[lst1, InterpolationOrder -> 1];
g = Interpolation[lst2, InterpolationOrder -> 1];
{x, f[x]} /. FindRoot[f[x] == g[x], {x, 2.1}]
(*  {2.28571, 5.28571}  *)

The default interpolation order, which is cubic, gives a slightly different answer:

f = Interpolation[lst1];
g = Interpolation[lst2];
{x, f[x]} /. FindRoot[f[x] == g[x], {x, 2.1}]
(*  {2.30278, 5.30278}  *)

This agrees exactly with the roots of the functions used to construct the lists because those functions, x^2 and x + 3, have degrees that do not exceed the interpolation order (and there are a sufficient number of data points).

Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • 1
    Note that whether the apparent improvement in accuracy from using the higher interpolation order is significant in a given problem should probably be considered in conjunction with the data, its source, and the model underlying the problem. – Michael E2 Oct 31 '15 at 16:23
7

Yet another way is to use the interpolation of one set of points as an appropriate mesh function in the plot of the other.

Here

mf = Interpolation[lst2];

and

plt = ListLinePlot[lst1, MeshFunctions -> (#2 - mf[#1] &), Mesh -> {{0}}, MeshStyle -> Red]

enter image description here

You can then extract the point with

plt// Cases[Normal@#, Point[a_] :> a, Infinity] &
(*{{2.28571, 5.28571}}*)
gpap
  • 9,707
  • 3
  • 24
  • 66
6

Following the comment by @J.M., here is a solution:

lst1 = Table[{x, x^2}, {x, 0, 5, 0.5}];
lst2 = Table[{x, x + 3}, {x, 0, 5, 0.5}];
GraphicsRow[{ListLinePlot[{lst1, lst2}], ListPlot[{lst1, lst2}]}]
f = Interpolation[lst1];
g = Interpolation[lst2];
cords = {x = x /. FindRoot[f[x] == g[x], {x, 2.1}], f[x]}
cordsExact = {x /. FindRoot[x^2 == x + 3, {x, 2.1}], x^2}

cheers!

an offer can't refuse
  • 1,745
  • 12
  • 23