Plotting of the sinosuidal functions according to the pixel in Python

62 Views Asked by At

I want to plot two sinusoidal functions. The generation of the plotting should be done according to the pixel size, like pixel by pixel. Any help regarding how to do this? The code I used to generate the waveform[ image attached in below]is below:

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML

amp = 0.5         # 1V        (Amplitude)
f = 20

frame_rate = 100
t = np.linspace(0, np.pi/2, 1000)
x = np.sin(t)
y = amp * (np.cos(2 * np.pi * f * t) + np.pi / 2)

# pixel size in inches (width,height)
dpi = 64
fig, ax = plt.subplots(figsize=(4, 4), dpi=dpi)
line, = ax.step(x, y)

plt.show()

def animate(frame, x, y, line):
    line.set_data(x[:frame], y[:frame])
    y_new = 0.5 * (np.cos(2 * np.pi * 20 * t[:frame]/2) + np.pi / 2)
    line.set_ydata(y_new)
    return line,

interval = 1000 / frame_rate

ani = FuncAnimation(fig, animate, frames=1000, interval=interval, fargs=[x, y, line])

HTML(ani.to_jshtml())

I thought to use the OpenCV library for this purpose. Is there any other easier option? Any help with codes, explanations and providing resources would be highly appreciated.

enter image description here

1

There are 1 best solutions below

2
AKX On

Here's a small example of how to plot a function with frame-varied parameters using Pillow, upscaling it 2x using nearest-neighbor interpolation so you can really see the pixels.

It saves the resulting animation as an animated GIF.

import numpy as np
from PIL import Image, ImageDraw


def func(phase):
    """
    Compute the x and y coordinates for the function points.

    Return two arrays, one for each dimension.
    """
    amp = 0.5
    f = 20

    t = np.linspace(0, np.pi / 2, 1000) + phase
    x = np.sin(t)
    y = amp * np.cos(2 * np.pi * f * t)
    return (x, y)


def rescale(arr, in_min, in_max, out_min, out_max):
    """
    Rescale the values in arr from [in_min, in_max] to [out_min, out_max].
    """
    return (arr - in_min) * (out_max - out_min) / (in_max - in_min) + out_min


def main():
    images = []
    num_frames = 150
    for frame in range(num_frames):
        img = Image.new("RGB", (400, 200), (0, 0, 0))
        draw = ImageDraw.Draw(img)
        phase = frame / num_frames * 2 * np.pi
        xs, ys = func(phase)

        # convert xs/ys into pixel coordinates as [(x, y)] tuples
        coords = list(
            zip(
                rescale(xs, 0, 1, 0, img.width),
                rescale(ys, -1, 1, 0, img.height),
            )
        )

        draw.line(coords, fill=(255, 255, 255), width=1)

        img = img.resize((img.width * 2, img.height * 2), resample=Image.NEAREST)
        images.append(img)
    images[0].save(
        "so77844220.gif",
        save_all=True,
        append_images=images[1:],
        loop=0,
        duration=50,
    )


if __name__ == "__main__":
    main()

For this code, the animation result (sans the upscaling to save SO's bandwidth) is:

enter image description here