Search code examples
pythonmatplotlibwhile-looppoint-in-polygon

While point in polygon plot points/lines fails (Circle.contains_point; Python; matplotlib; pyplot)


My task: Plot an initial point and calculate new point positions (x, y) while points are in a circle.

My problem: Using a while loop to perform this fails to run the code block as it incorrectly determines the circle doesn't contain the point (fig 1). However, using a for loop it can be seen that multiple points reside in the circle, but still incorrectly identifies that points don't exist in the circle (fig 2).

Additional info: I also can't seem to get lines instead of points to be plotted (e.g. using pyplot.plot(x, y, '-')). If there are more streamlined methods, for instance in plotting the circle/points/lines, or the entire approach I'd be interested to see them. I appreciate any help that can be offered.

After much searching here and elsewhere I've come as far as the following code:

# IMPORT LIBRARIES ####
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mPath
import matplotlib.patches as mPatches


# CREATE CIRCLE ####
# Input circle radius
circleRadius = 2

# Create circle (arguments: centre, radius, face colour (fc), edge colour (ec), alpha)
circle = mPatches.Circle((0, 0), radius = circleRadius, fc = 'm', alpha = 0.3)

# Plot circle
fig1, ax = plt.subplots()
ax.add_patch(circle)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_aspect('equal')


# CREATE POINTS ####
# Input coordinates
x0 = -1
y0 = 0.5
# Assignment for equation
x = x0
y = y0

# Store
curr_pt = [x, y]
counter = 0

# Plot 1st point (x, y)
plt.plot(x, y, '.c')

# Pre-checks
print(circle.contains_point([x, y]))
print(counter)
print(x0, y0)
print(x, y)

# Plot points 
while circle.contains_point([x, y]): # see 1st figure
#for i in range(5):                  # uncomment this line (for) and comment above line (while) see 2nd figure
    xnew = x**2 - y**2 + x0
    ynew = 2 * x * y + y0
    x = xnew
    y = ynew
    # Update current point
    curr_pt = [x, y]
    # Plot point (x, y)
    plt.plot(x, y, '.c')
    counter += 1

# Post-checks
print(circle.contains_point([x, y]))
print(counter)
print(x0, y0)
print(x, y)
print(xnew, ynew) # note this check will output error with while loop as they will not be defined

# Print plot
plt.show()

Output:

# while loop (Fig 1)
False
0
-1 0.5
-1 0.5
False
0
-1 0.5
-1 0.5

Fig 1 (while loop)

# for loop (Fig 2)
False
0
-1 0.5
-1 0.5
False
5
-1 0.5
5.063203536206856 -4.162733919918537
5.063203536206856 -4.162733919918537

Fig 2 (for loop)


Solution

  • Update:

    Utilising the methods outlined in these answers:

    My amended code now correctly identifies if points are in a Circle and executes a while loop according to contains_point().

    Amended code:

    # IMPORT LIBRARIES ####
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.path as mPath
    import matplotlib.patches as mPatches
    
    
    # CREATE CIRCLE ####
    # Input circle radius
    circleRadius = 2
    
    # Create circle (arguments: centre, radius, face colour (fc), edge colour (ec), alpha)
    circle = mPatches.Circle((0, 0), radius = circleRadius, fc = 'm', alpha = 0.3)
    
    # Get path and 2D affine transformation
    pathC = circle.get_path()
    transformC = circle.get_transform()
        
    # Apply transformation to the path
    transPath = transformC.transform_path(pathC)
        
    # Get path of transformed circle
    polygon = mPatches.PathPatch(transPath, fc = 'm', alpha = 0.3)
    
    
    # CREATE POINTS ####
    # Input initial coordinates
    x0 = -1
    y0 = 0.5
    # Assignment for new point equation
    x = x0
    y = y0
    # Store
    curr_pt = (x, y)
    all_x = []
    all_y = []
    
    # Iterations required to escape circle
    counter = 0
    
    # Pre-check
    cp1 = polygon.contains_point(curr_pt)
    print("Pre-loop checks:")
    print("Polygon contains point:", cp1)
    print("Counter:", counter)
    print("(x, y):", x, y)
    print("")
    
    # Create figure and single subplot
    fig, ax = plt.subplots()
    
    # Plot initial point (x, y)
    ax.scatter(curr_pt[0], curr_pt[1], color = 'c')
    
    # Plot new points
    while polygon.contains_point(curr_pt):    
        xnew = x**2 - y**2 + x0
        ynew = 2 * x * y + y0
        x = xnew
        y = ynew
        # Update current point
        curr_pt = (x, y)
        # Update x, y lists for plotting lines
        all_x.append(curr_pt[0])
        all_y.append(curr_pt[1])
        # Plot new point
        ax.scatter(curr_pt[0], curr_pt[1], color = 'c')
        # Increment counter
        counter += 1
        if counter == 50:
            break
    
    # Post-check
    cp2 = polygon.contains_point(curr_pt)
    print("Post-loop checks:")
    print("Polygon contains point:", cp2)
    print("Counter:", counter)
    print("(x, y):", x, y)
    print("(xnew, ynew):", xnew, ynew)
    
    
    # CREATE PLOT ####
    # Plot lines
    ax.plot(all_x, all_y, color = 'c')
    # Plot circle
    ax.add_patch(polygon)
    
    # Print plot
    ax.set_aspect(1.0)
    fig.savefig("Correct point in polygon (points and lines).png")
    plt.show()
    

    Output:

    Pre-loop checks:
    Polygon contains point: True
    Counter: 0
    (x, y): -1 0.5
    
    Post-loop checks:
    Polygon contains point: False
    Counter: 4
    (x, y): -2.6183929443359375 0.890380859375
    (xnew, ynew): -2.6183929443359375 0.890380859375
    

    enter image description here