4

I'm trying to draw elliptical lines using matplotlib to connect two circles but would like to make it so the elliptical lines do not intersect either circle.

Currently my design has resulted in this: enter image description here

which as you can see has lines going through both circle A and B. I decided to use matplotlib.patches.Arc since I didn't want it filled and it allowed me to draw a left and right part. Here is what I have:

from matplotlib import pyplot
from matplotlib.patches import Arc
import math

def calculate_perimeter(a, b):
    perimeter = math.pi * (3*(a+b) - math.sqrt( (3*a + b) * (a + 3*b) ))
    return perimeter

def draw_circle(xy, radius, text):
    circle = pyplot.Circle(xy, radius=radius,     fill=False)
    pyplot.gca().add_patch(circle)
    pyplot.gca().annotate(text, xy=xy,     fontsize=10, ha='center', va='center')

def draw_arc(xy1, xy2, a, b, theta1, theta2):
    # Calculate center of the elliptical arc
    center = (xy1[0], (xy1[1] + xy2[1])/2.0)
    arc = Arc(center, a, b, theta1=theta1, theta2=theta2)
    pyplot.gca().add_patch(arc)

if __name__ == '__main__':
    pyplot.figure()
    center_circle1 = (5, 5)
    center_circle2 = (5, 20)
    dist_y = center_circle2[1] - center_circle1[1]
    adjustment = 5.3 # @TODO: How do I calculate what this needs to be?
    # Circles
    draw_circle(center_circle1, 1, 'A')
    draw_circle(center_circle2, 1, 'B')
    # Draw right side of arc
    theta1 = 270.0 + adjustment
    theta2 = 90.0 - adjustment
    draw_arc(center_circle1, center_circle2, 3, dist_y, theta1, theta2)
    # Draw left side of arc
    theta1 = 90.0 + adjustment
    theta2 = 270.0 - adjustment
    draw_arc(center_circle1, center_circle2, 3, dist_y, theta1, theta2)
    pyplot.axis('scaled')
    pyplot.axis('off')
    pyplot.show()

For instance when I put adjustment = 5.3 I get: enter image description here

If I zoom in on this area though it's easy to see it does not line up: enter image description here

My question then becomes, how do I calculate what adjustment should be?

I thought I would be able to calculate the perimeter if I consider it a complete ellipse and subtract the amount that overlaps in one of the circles and use that to get the adjustment, but I'm not sure if that would work or how to calculate how much overlaps inside. Any help on this would be appreciated.

Chrispresso
  • 3,660
  • 2
  • 19
  • 31

1 Answers1

4

Rather than adjusting the figure manually, consider using the zorder in the Patch constructor.

The various artists on a plot are stacked upon each other vertically, with those with the highest zorder on top. By setting the zorder, therefore, you will cause the circles to be drawn over the ellipse, obscuring it.

Example code:

from matplotlib import pyplot as plt
from matplotlib.patches import Circle, Arc

fig, ax = plt.subplots(figsize=(6, 6))

ax.add_patch(Circle((0.5, 0.75), 0.05, edgecolor='black', facecolor='white', zorder=3))
ax.add_patch(Circle((0.5, 0.25), 0.05, edgecolor='black', facecolor='white', zorder=3))
ax.add_patch(Arc((0.5, 0.5), 0.1, 0.5))

That generates

this.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
gmds
  • 19,325
  • 4
  • 32
  • 58
  • 1
    This is probably the answer the OP is asking for. Otherwise, it is more of a math problem, asking how to calculate the angle at which the intersection point between the circle and the ellipse lies. This is not too hard, as the equation for the ellipse and circles are known and they can be solved for each other to obtain the coordinates of the intersection (and then some trigonometry is all that's needed to obtain the required angle). But it's a question that belongs on https://math.stackexchange.com – Grismar Feb 05 '19 at 02:45
  • Thanks for that. I guess I don't always have to try to solve things with math ;) – Chrispresso Feb 05 '19 at 22:32