-1

This problem is different than what already reported because I have limited information to join the points. I am trying to join three points using a curve. I don't have any other information to join the curves. I want and have to achieve this for any given points. An example of three points is given below:

Point1 = [19.616, 8.171] 
Point2 = [28.7, 5.727]
Point3 = [34.506, 0.012125]

My code is given below:

def curve_line(point1, point2):
    a = (point2[1] - point1[1])/(np.cosh(point2[0]) - np.cosh(point1[0]))
    b = point1[1] - a*np.sinh(point1[0])
    print(a,b,point1,point2)
    x = np.linspace(point1[0], point2[0],100)
    c = [b,  -a,  0.65636074, -0.05219088]
    y = a*np.cosh(x) + b 
    return x,y

x1,y1 = curve_line(point1, point2)
x2,y2 = curve_line(point2, point3)
plt.plot(x1,y1)
plt.plot(x2,y2) 

My actual output and expected output are given below:

enter image description here

Msquare
  • 775
  • 7
  • 17
  • 1
    Possible duplicate of [Plot smooth line with PyPlot](https://stackoverflow.com/questions/5283649/plot-smooth-line-with-pyplot) – meowgoesthedog Aug 01 '19 at 14:15
  • 1
    @meowgoesthedogq No duplicate of "Plot smooth line with PyPlot" in my opinion, because the OP is struggling to fit a **particular formulation** to their sparse available data and not to better the appearance of an already reasonably dense curve. – gboffi Aug 01 '19 at 14:37
  • @gboffi thanks for clarifying this. – Msquare Aug 01 '19 at 14:39

1 Answers1

2

You do it exactly the same way as with a curve. If you have a function with 3 parameters and fit it to three points, you'll get an exact solution with the curve going through all 3 points (it boils down to solving 3 equations with 3 unknowns):

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

x = np.array([ 1.92, 30, 34.21])
y = np.array([8.30, 5, 0.06])

def fun(x, a, b, c):
    return a * np.cosh(b * x )+ c

coef,_ = curve_fit(fun, x, y)

plt.plot(x, y, 'o', label='Original points')
plt.plot(np.linspace(x[0],x[-1]), fun(np.linspace(x[0],x[-1]), *coef), label=f'Model: %5.3f cosh(%4.2f x) + %4.2f' % tuple(coef) )
plt.legend()
plt.show()

enter image description here

In some cases you'll have to give some sensible starting values. These values can be obtained from a rough sketch of the curve, an online function graphing tool may be helpful in understanding the influence of the individual parameters.

Example:

x = np.array([ 19.616, 28.7, 34.506])
y = np.array([8.171, 5.727, 0.012125])
p0 = [-0.1, 0.5, 8]
coef,_ = curve_fit(fun, x, y, p0)
Stef
  • 28,728
  • 2
  • 24
  • 52
  • No - our function has 3 parameters, so we need minimum 3 points. With two points you only can unambiguoulsy determin a curve with two parameters (= a straight line). Otherwise you'll have to manually fix one of the three parameters and then you can fit the remaining two. – Stef Aug 01 '19 at 14:32
  • Thanks for the explanation. My question has three points `x = np.array([19.616, 28.7, 34.506]) y = np.array([8.171, 5.727, 0.012125])` but you considered different points. I tried for this points and I got following response `RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 800.` – Msquare Aug 01 '19 at 14:36
  • As I wrote in the [previsous answer](https://stackoverflow.com/a/57307439/3944322), in some cases you'll have to provide sensible starting values, e.g. `p0 = [-0.1, 0.5, 8]` then do `coef,_ = curve_fit(fun, x, y, p0)`. – Stef Aug 01 '19 at 14:43
  • I am new to python. Could you please edit your answer to include starting values? – Msquare Aug 01 '19 at 14:45
  • I am new to python. Could you please edit your answer to include starting values? I could do it but i don't know where to include these values – Msquare Aug 01 '19 at 14:46
  • 1
    I've included an example at the end of my answer. – Stef Aug 01 '19 at 14:52
  • I am fitting different points with different magnitudes. Looks like! the initial coefficients `p0` is nor merging. So, I have to do it trial and error. Sometimes, I am not successful. Is their a way to guess the `p0` based on the thre input points provided. – Msquare Aug 01 '19 at 19:24
  • try `b=0.5`, `a=(y[0]-y[-1])/(np.cosh(b*x[0])-np.cosh(b*x[-1]))`, `c=y[0]-a*np.cosh(b*x[0])`, `np.array([a,b,c])` (each on a separate line), this should give fairly sensible starting values – Stef Aug 01 '19 at 21:02
  • I tried this. Got following response: `RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 800.` – Msquare Aug 02 '19 at 22:48
  • if you send me the three points for which it doesn't work I'll have a look at it on Monday (can't promise though) – Stef Aug 02 '19 at 22:53
  • Thanks for quick response. I am giving you a different set of points to try. Set1 `([36.486, 1.747, 11.347] [0.0165454545454545, 8.966, 8.911])`, Set2 `([20.913, 30.297, 36.486] [8.828, 6.745, 0.0165454545454545])` Set3 `([435.088, 1.847, 13.709] [0.1766, 9.021, 9.007])`. These are different sets I am trying to build a curve individually. Thanks for spending time. – Msquare Aug 02 '19 at 23:04
  • 1
    Set the initial guess for `b` to 0.1 instead of 0.5. Works with all three examples you gave. – Stef Aug 05 '19 at 07:30