1

I have a figure that contains both a curve plot and a corresponding image. I'd like for the two of them to shift in sync with one another -- so that the white region of the image follows the location in the curve where all three curves match up. (For the curious, this is intended as a simple simulation of a multiwavelength interferogram.)

The three curves in the plot are copied point-by-point into the into the R, G, and B channels of the image frame. As a result, I expected the two to be naturally in sync. However, in the animation one can see that the curves shift at a faster rate than the colors in the image.

After trying a number of adjustments (aspect ratio of the image, changing the image "extent", etc.) I have so far failed to locate the problem.

from numpy import *
import matplotlib.pyplot as plt
from matplotlib import animation

npts = 501
wavelength_blue = 0.45
wavelength_green = 0.55
wavelength_red = 0.65
z = 1.5 * linspace(-0.75, 0.75, npts)      ## distance in microns
nframes = 100
maxshift = 0.55     ## in microns of distance
img_height = 100
img = 255 * ones((img_height,npts,3), 'uint8')

(fig,axes) = plt.subplots(2, num='propagation_phase_shifted')
p1 = axes[0].plot([], [], 'b-')
p2 = axes[0].plot([], [], 'g-')
p3 = axes[0].plot([], [], 'r-')
axes[0].set_xlim((-0.8,0.8))
axes[0].set_ylim((-0.1,1.1))
p4 = axes[1].imshow(img, extent=[-0.8,0.8,-0.1,1.1], aspect=1/3)

axes[0].xaxis.set_label_position('top')
axes[0].xaxis.set_ticks_position('top')
axes[0].set_xlabel('z-distance (um)')
axes[0].set_ylabel('wave amplitude')
axes[0].tick_params(axis='x', direction='out')
plt.subplots_adjust(hspace=0.05)

def animate(n):
    shift = (n / (nframes - 1.0)) * maxshift
    phi_red = 2.0 * pi * (z-shift) / wavelength_red
    phi_green = 2.0 * pi * (z-shift) / wavelength_green
    phi_blue = 2.0 * pi * (z-shift) / wavelength_blue

    y_red = 0.5 * (1.0 + cos(phi_red))
    y_green = 0.5 * (1.0 + cos(phi_green))
    y_blue = 0.5 * (1.0 + cos(phi_blue))

    for x in range(img_height):
        img[x,:,0] = uint8(255 * y_red)
        img[x,:,1] = uint8(255 * y_green)
        img[x,:,2] = uint8(255 * y_blue)

    p1[0].set_data(z, y_red)
    p2[0].set_data(z, y_green)
    p3[0].set_data(z, y_blue)
    p4.set_data(img)
    return(p1[0],p2[0],p3[0],p4)

anim = animation.FuncAnimation(fig, animate, frames=nframes, interval=20, blit=True)
FFwriter = animation.FFMpegWriter(fps=30)
anim.save('result.mp4', writer=FFwriter)

plt.show()

enter image description here

1

1 Answer 1

2

I think the problem occurs when you convert your distance in microns. The same data is stretched between -1.125..1.125 on the top figure (1.5*0.75=1.125) and -0.8..0.8 on the bottom one. The top one then appear to move faster.

Fixing the intervals should work. Also if I'm not mistaken, you interverted red and blue in the top plot:

from numpy import *
import matplotlib.pyplot as plt
from matplotlib import animation

npts = 501
wavelength_blue = 0.45
wavelength_green = 0.55
wavelength_red = 0.65
z = 1.5 * linspace(-0.75, 0.75, npts)      ## distance in microns
nframes = 100
maxshift = 0.55     ## in microns of distance
img_height = 100
img = 255 * ones((img_height,npts,3), 'uint8')

(fig,axes) = plt.subplots(2, num='propagation_phase_shifted')
p1 = axes[0].plot([], [], 'r-')     # <--------- replacing b with r
p2 = axes[0].plot([], [], 'g-')
p3 = axes[0].plot([], [], 'b-')     # <--------- replacing r with b
axes[0].set_xlim((-1.125,1.125))    # <--------- fixing interval
axes[0].set_ylim((-0.1,1.1))
p4 = axes[1].imshow(img, extent=[-1.125,1.125,-0.1,1.1], aspect=1/3)    # <--------- fixing interval

axes[0].xaxis.set_label_position('top')
axes[0].xaxis.set_ticks_position('top')
axes[0].set_xlabel('z-distance (um)')
axes[0].set_ylabel('wave amplitude')
axes[0].tick_params(axis='x', direction='out')
plt.subplots_adjust(hspace=0.05)

def animate(n):
    shift = (n / (nframes - 1.0)) * maxshift
    phi_red = 2.0 * pi * (z-shift) / wavelength_red
    phi_green = 2.0 * pi * (z-shift) / wavelength_green
    phi_blue = 2.0 * pi * (z-shift) / wavelength_blue

    y_red = 0.5 * (1.0 + cos(phi_red))
    y_green = 0.5 * (1.0 + cos(phi_green))
    y_blue = 0.5 * (1.0 + cos(phi_blue))

    for x in range(img_height):
        img[x,:,0] = uint8(255 * y_red)
        img[x,:,1] = uint8(255 * y_green)
        img[x,:,2] = uint8(255 * y_blue)

    p1[0].set_data(z, y_red)
    p2[0].set_data(z, y_green)
    p3[0].set_data(z, y_blue)
    p4.set_data(img)
    return(p1[0],p2[0],p3[0],p4)

anim = animation.FuncAnimation(fig, animate, frames=nframes, interval=20, blit=True)
FFwriter = animation.FFMpegWriter(fps=30)
anim.save('result.mp4', writer=FFwriter)

plt.show()
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the smooth fix! So I unsuspectingly truncated the upper plot but not the lower one...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.