Search code examples
pythonmatplotlibcontour

Plotting contours in python


I have a dataset which consists of three values (x, y, z).

z is a value given by a specific function of x and y that I don't have access to.

The data points are
(500,10,1.543),(500,20,1.432) ... (500,100,0.534) , (600,10,1.232),(600,20,1.432) ... till x value reaches (5000,100,0.032)

I want to plot it using a contour plot.

I tried:

x = np.array(a[0])  # Your x values
y = np.array(a[1]) # Your y values
z = np.array(a[2])  # Corresponding z values

# Create a grid of coordinates
xi = np.linspace(x.min(), x.max(), 100)
yi = np.linspace(y.min(), y.max(), 100)
Xi, Yi = np.meshgrid(xi, yi)

# Interpolate z values onto the grid
from scipy.interpolate import griddata
Zi = griddata((x, y), z, (Xi, Yi), method='linear')

# Create the contour plot
plt.figure(figsize=(10, 8))
plt.contourf(Xi, Yi, Zi, cmap='viridis')
contours = plt.contour(Xi, Yi, Zi, levels=10, colors='black')

# Add colorbar
plt.colorbar(label='Z Value')

# Add scatter plot of original data points
plt.scatter(x, y, color='red', alpha=0.5)

# Add labels and title
plt.title('Contour Plot of X-Y-Z Data')
plt.xlabel('X')
plt.ylabel('Y')

# Add labels to contours
plt.clabel(contours, inline=True, fontsize=10)

plt.show()

The error I get is:

"message": "QH6013 qhull input error: input is less than 3-dimensional since all points have the same x coordinate  50

Solution

  • image

    If your data is in the array a, and you have 46 points [500, 600, ..., 4900, 5000] on the x axis and 10 points [10, 20, ..., 90, 100] on the y axis, you can reshape the rows to a form suitable to be contoured

    X, Y, Z = [arr.reshape(46, 10) for arr in a]
    

    next, it's just

    filled = plt.contourf(X, Y, Z)
    contours = plt.contour(X, Y, Z)
    plt.colorbar(filled)
    plt.clabel(contours)
    

    The top figure was generated using this code

    import matplotlib.pyplot as plt
    import numpy as np
    from itertools import product
    
    # generate fake data
    a = np.array([[x, y, z] for z, (x, y) in 
        enumerate(product(range(500, 5001, 100), range(10, 101, 10)))]).T
    
    # unpack data in 3 46×10 arrays
    X, Y, Z = np.array([v.reshape(46, 10) for v in a])
    
    # prepare for plotting
    levels  = 11
    colors  = ['w']*(levels//2+1)
    colors += ['k']*((levels//2+1) if levels%2 else levels//2)
    
    # plotting
    filled = plt.contourf(X, Y, Z, levels=levels)
    plt.colorbar(filled)
    contours = plt.contour(X, Y, Z,
                           levels=levels, linewidths=0.75,
                           colors=colors)
    plt.clabel(contours, fontsize=11)
    plt.show()
    

    The choice of colors for the contour lines/labels in the code above works for perceptually uniform colormaps, dark to light, and you need to rework the choice if it's a light to dark colormap or it's a diverging colormaps. Don't use 'jet' ;-)