Search code examples
pythonimagepython-3.xmatplotlibaxis-labels

nonlinear scaling image in figure axis matplotlib


enter image description hereI hope I have not over-looked as previously asked question. I don't think so. I have an image of a spectrum. I have several laser lines for calibration. Since the laser lines and the spectrum were collected in the same way they should be correlated in pixel distance. The relationship between pixel number and wavelength is nonlinear. I have fit the pixel number along the x-axis against the wavelength of the laser lines (blue @ 405nm green @ 532nm and red @ 650nm) using a 3rd degree polynomial with high correlation. I want to plot the spectrum by computing the wavelength( nm) directly from the pixel number and display the wavelength beneath the spectrum. Is this possible without overlapping the image on another figure? spectrograph of Laser Lines

import matplotlib.pyplot as plt
from scipy import ndimage
from pylab import *
import numpy as np

import skimage

image= laser_lines

print(image.shape)


for i in range(image.shape[1]):
    x=i^3*-3.119E-6+2.926E-3*i^2+0.173*i+269.593
for j in range(image.shape[0]):
    y=image[i,j]
imshow(image)    


plt.show()

Solution

  • Probably the easiest option is to use a pcolormesh instead of an imshow plot. The pcolormesh shows the edges of a grid, such that you might simply transform the original grid using the functional dependence between pixels and wavelength to define the edges of each pixel in terms of wavelength.

    import numpy as np 
    import matplotlib.pyplot as plt
    
    image = np.sort(np.random.randint(0,256,size=(400,600)),axis=0)
    
    
    f = lambda i: i**3*-3.119E-6+2.926E-3*i**2+0.173*i+269.593
    xi = np.arange(0,image.shape[1]+1)-0.5
    yi = np.arange(0,image.shape[0]+1)-0.5
    Xi, Yi = np.meshgrid(xi, yi)
    
    Xw = f(Xi)
    
    fig, (ax) = plt.subplots(figsize=(8,4))
    
    ax.pcolormesh(Xw, Yi, image)
    
    ax.set_xlabel("wavelength [nm]")
    plt.show()
    

    enter image description here

    If the image has 3 colorchannels, you need to use the color argument of pcolormesh to set the color of each pixel, as shown in this question: Plotting an irregularly-spaced RGB image in Python

    import numpy as np 
    import matplotlib.pyplot as plt
    
    r = np.sort(np.random.randint(0,256,size=(200,600)),axis=1)
    g = np.sort(np.random.randint(0,256,size=(200,600)),axis=0)
    b = np.sort(np.random.randint(0,256,size=(200,600)),axis=1)
    image = np.dstack([r, g, b])
    
    color = image.reshape((image.shape[0]*image.shape[1],image.shape[2]))
    if color.max() > 1.:
        color = color/255.
    
    f = lambda i: i**3*-3.119E-6+2.926E-3*i**2+0.173*i+269.593
    xi = np.arange(0,image.shape[1]+1)-0.5
    yi = np.arange(0,image.shape[0]+1)-0.5
    Xi, Yi = np.meshgrid(xi, yi)
    
    Xw = f(Xi)
    
    fig, (ax) = plt.subplots(figsize=(8,4))
    
    pc = ax.pcolormesh(Xw, Yi, Xw, color=color )
    pc.set_array(None)
    ax.set_xlabel("wavelength [nm]")
    plt.show()