1

I'm trying to generate a non-linear curve between two integers, let's say 0 and 25 that matches up to this curve here:

enter image description here

It seems like a stupid simple problem, the curve I need even looks like part of a circle, so generating a large circle, and taking the points at the bottom right would solve this, but I don't know how to do any of that.

All I need is a list from 0 to 25 with the curve as a part of that list, if that makes sense. Starting slowly increasing, then speeding up, then slowing down near the end.

I've tried this with a similar result, but it's not at the exact angle/curve.

x=[]
y=range(25)

for i in range(25):
    x.append((i**.25)**2)

plt.plot(x, y)
plt.show()

enter image description here

Thanks

Shane Smiskol
  • 952
  • 1
  • 11
  • 38
  • Do you have the original data used to generate the first curve? – Carlos Roldán Mar 28 '19 at 01:34
  • If you want this exact curve you'll need to do curve fitting https://stackoverflow.com/questions/19165259/python-numpy-scipy-curve-fitting. other wise just do `x = [-(25-(i/5)**2)**0.5+5 for i in range(25)]` – Recessive Mar 28 '19 at 01:38
  • 1
    Thanks @Recessive! That link helped. Didn't know about curve fitting until just now haha – Shane Smiskol Mar 28 '19 at 02:14

1 Answers1

3

If you really want to have the same curve, you could load the plot image, and use PIL to get every blue pixel:

from urllib.request import urlopen
from PIL import Image

img = Image.open(urlopen('https://i.stack.imgur.com/NpiMq.png'))
X = []
Y = []
for x in range(img.size[0]):
    for y in range(img.size[1]):
        r, g, b, a = img.getpixel((x, y))
        if b > r and b > g:
            X.append(x)
            Y.append(y)

Then, knowing that (0, 20) in the plot is the pixel (63, 355), and (25, 160) in the plot is the pixel (516, 32), you can transform pixel coordinates to data points:

X = [(x - 63) * (25 - 0) / (516 - 63) + 0 for x in X]
Y = [(y - 355) * (160 - 20) / (32 - 355) + 20 for y in Y]

Finally, you can use numpy polyfit to get a polynomial fit to the points you previously obtained:

>>> np.polyfit(X, Y, 3)
[ 8.23918277e-03 -7.33330644e-02  2.60046715e+00  2.03012850e+01]

And then, plot the result using poly1d to get a function that given a x value returns its y value:

import numpy as np
from matplotlib import pyplot as plt

x2y = np.poly1d(np.polyfit(X, Y, 3))
new_X = [x / 10 for x in range(250)]
new_Y = [x2y(x) for x in new_X]
plt.plot(new_X, new_Y)
plt.show()

Output of the plot

Carlos Roldán
  • 902
  • 1
  • 9
  • 19