8

I want to give the points [0,1],[1,0] and [0,-1] to python and plot the circle that passes over them. Does exists a python module that make this? I have tried using matplotlib:

import matplotlib.pyplot as plt
plt.plot([0,1,0],[1,0,-1])
plt.show()

But only gave me two lines.

iam_agf
  • 639
  • 2
  • 9
  • 20

5 Answers5

17

There was a "code golf" question exactly matching this (except that the circle's equation was requested, rather than plotting it) -- see https://codegolf.stackexchange.com/questions/2289/circle-through-three-points . Unraveling the first and shortest (Python) solution into more readable, less-hacky form to match your exact specs - but keeping the core idea of using complex numbers for simpler calculations:

x, y, z = 0+1j, 1+0j, 0-1j
w = z-x
w /= y-x
c = (x-y)*(w-abs(w)**2)/2j/w.imag-x
print '(x%+.3f)^2+(y%+.3f)^2 = %.3f^2' % (c.real, c.imag, abs(c+x))

OK, this still "prints the equation" rather than "plotting the circle", but, we're getting close:-). To actually plot the circle in matplotlib, see e.g plot a circle with pyplot -- in the solution above, c is the (negated) center of the circle (as a complex number, so use .real and .imag for the x/y coordinates), and abs(c+x) the radius (a real number, abs makes it so).

Community
  • 1
  • 1
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • This is the useful one because I will work with complex numbers. I forgot that it's easier to obtain the center and radius by this way. – iam_agf Mar 07 '15 at 02:50
  • 4
    I guess seeing your nick clearly honoring Évariste Galois guided my subconscious towards this mathematically elegant idea:-). Remembering a guy who died at 1/3rd my age, leaving behind just 60 pages of notes revolutionizing **two** key branches of maths, keeps me appropriately humble (plus, I'm 1/8th French, so it also helps keep me appropriately proud:-). – Alex Martelli Mar 07 '15 at 02:59
  • Is nice to see a person that knows of him. I'm an algebra lover because of his discoveries :-). – iam_agf Mar 07 '15 at 03:16
  • Perfect! And if your input is in Cartesian, first convert the 3 points to complex coordinates, e.g.: `x, y, z = complex(2,2), complex(6,2), complex(2,6)` – stason Jun 22 '18 at 23:07
  • What is the explanation of the math here? It seems to me like it's not exactly the same as [this](https://math.stackexchange.com/a/1145021/281166) and I don't fully get it yet – lucidbrot Mar 02 '21 at 22:25
  • @iam_agf I know this is six years old, but do you maybe still get it? I find the solution here very elegant, but I did not manage to understand it now despite investing a few hours. I assume it should be obvious once one gets it? – lucidbrot Mar 07 '21 at 11:22
  • 1
    I don't remember if at some point I reached to understand how he did it, since, as how he said, he adapted a solution from a code golf question, but I remember I looked for my own way to calculate it because the only thing that lighted me up was the phrase "complex numbers". In fact I consider easier your link posted since it's explained in an extended way. – iam_agf Mar 07 '21 at 11:58
  • 1
    @iam_agf I got it now! I added an explanation in my [answer](https://stackoverflow.com/a/66518545/2550406) to make life easier for future visitors. – lucidbrot Mar 07 '21 at 16:07
14

This code also lets you easily check whether the 3 points form a line or not.

def define_circle(p1, p2, p3):
    """
    Returns the center and radius of the circle passing the given 3 points.
    In case the 3 points form a line, returns (None, infinity).
    """
    temp = p2[0] * p2[0] + p2[1] * p2[1]
    bc = (p1[0] * p1[0] + p1[1] * p1[1] - temp) / 2
    cd = (temp - p3[0] * p3[0] - p3[1] * p3[1]) / 2
    det = (p1[0] - p2[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p2[1])
    
    if abs(det) < 1.0e-6:
        return (None, np.inf)
    
    # Center of circle
    cx = (bc*(p2[1] - p3[1]) - cd*(p1[1] - p2[1])) / det
    cy = ((p1[0] - p2[0]) * cd - (p2[0] - p3[0]) * bc) / det
    
    radius = np.sqrt((cx - p1[0])**2 + (cy - p1[1])**2)
    return ((cx, cy), radius)

And to solve the original question:

center, radius = define_circle((0,1), (1,0), (0,-1))
if center is not None:
    plt.figure(figsize=(4, 4))
    circle = plt.Circle(center, radius)
    plt.gcf().gca().add_artist(circle)

(Adjusted from here)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
DieterDP
  • 4,039
  • 2
  • 29
  • 38
3

I was very curious why the accepted answer by Alex Martelli works. And I had to create a report for my lecture anyway, so I'm pasting it here for posterity.

enter image description here enter image description here

lucidbrot
  • 5,378
  • 3
  • 39
  • 68
2

Given three points whose coordinates are:

(p,t) (q,u) (s,z)

...the equation of the circle defined by those three points is:

x^2 + y^2 + Ax + By + C = 0

where:

A=((u-t)*z^2+(-u^2+t^2-q^2+p^2)*z+t*u^2+(-t^2+s^2-p^2)*u+(q^2-s^2)*t)/((q-p)*z+(p-s)*u+(s-q)*t)

B=-((q-p)*z^2+(p-s)*u^2+(s-q)*t^2+(q-p)*s^2+(p^2-q^2)*s+p*q^2-p^2*q)/((q-p)*z+(p-s)*u+(s-q)*t)

C=-((p*u-q*t)*z^2+(-p*u^2+q*t^2-p*q^2+p^2*q)*z+s*t*u^2+(-s*t^2+p*s^2-p^2*s)*u+(q^2*s-q*s^2)*t)/((q-p)*z+(p-s)*u+(s-q)*t)

The above is the general solution. You can put the formulas for A, B, and C into your program and find the equation for any circle, given 3 points.

For your particular problem with points (0,1) (1,0) (0,-1) you will get:

A=0

B=0

C=-1

... so the equation will be

x^2 + y^2 -1 = 0 (the unit circle)

Rutherford
  • 21
  • 2
1

To draw a circle in matplotlib, first you need to declare an artist

circle = plt.Circle((0,0), 2)

you then have to add that artist to an instance of axes:

fig, ax = plt.subplots()
ax.add_artist(circle)

then you can draw it safely.

plt.show()

Notice that artist Circle takes (x,y) coordinates of the circle's center, and radius r. That means you're going to have to calculate those values yourself.

ljetibo
  • 3,048
  • 19
  • 25