Search code examples
pythonnumpymatplotlibtextlabel

How to draw labels in ellipses as in a contour plot?


Problem

I am trying to plot a figure similar to the following image:

enter image description here

I use the following code:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

contours = [30, 40, 50]

v = np.array([15, 18])
colours = [
    (0.0, 0.26666666666666666, 0.10588235294117647, 1.0),
    (0.2917647058823529, 0.6886582083813917, 0.3827758554402153, 1.0),
    (0.8274509803921569, 0.9325490196078431, 0.8031372549019608, 1.0)
]

def ellipseFunction(x, v):
        return np.sqrt((x[0]/v[0])**2 + (x[1]/v[1])**2)

ellipses = [Ellipse((0, 0), width= 2*v[0]*contours[l], height=2*v[1]*contours[l], ec = colours[l], fc= "none") for l in range(len(contours))]

x = np.linspace(-2500, 2500, 100)
y = np.linspace(-2500, 2500, 100)
plt.figure()
plt.pcolormesh(x, y, ellipseFunction(np.meshgrid(x, y), v).T, cmap = 'plasma', zorder = -1, vmax = 150)
plt.gca().set_aspect(1./plt.gca().get_data_ratio())
for l in range(len(contours)):
    plt.gca().add_patch(ellipses[l])

Output:

enter image description here

Question

How can I add the ellipse labels (30, 40 and 50) in the edge of the ellipses as in the contour plot from the original image?


Solution

  • You can use the plt.contour with the argument levels to plot the contours then add the labels with clabel.

    Full codes :

    import numpy as np
    import matplotlib.pyplot as plt
    
    contours = [30, 40, 50]
    
    v = np.array([15, 18])
    colours = [
        (0.0, 0.26666666666666666, 0.10588235294117647, 1.0),
        (0.2917647058823529, 0.6886582083813917, 0.3827758554402153, 1.0),
        (0.8274509803921569, 0.9325490196078431, 0.8031372549019608, 1.0)
    ]
    
    def ellipseFunction(x, v):
            return np.sqrt((x[0]/v[0])**2 + (x[1]/v[1])**2)
    
    
    x = np.linspace(-2500, 2500, 100)
    y = np.linspace(-2500, 2500, 100)
    z = ellipseFunction(np.meshgrid(x, y), v).T
    fig, ax = plt.subplots()
    im = plt.pcolormesh(x, y, z, cmap = 'plasma', zorder = -1, vmax = 150)
    plt.gca().set_aspect(1./plt.gca().get_data_ratio())
    CS = plt.contour(x, y, z, levels=contours)
    ax.clabel(CS)
    plt.colorbar(im)
    

    The output :

    enter image description here