NOTE: this is by no means a good solution, I am writing this answer for the purpose of you having an answer at all, no matter how good or bad
My approach is to create an image and treat each pixel as a dot on a graph by plugging in the x coordinate of the pixel into a function that returns a number that is checked against the y coordinate of the pixel. If the result of the function is equal to the y coordinate, the pixel's color is changed. I added a few options to customize the look of the graph. Here is the function (it is only a prototype mean and is not at its potential efficiency, if you like this approach I can improve the code):
from numbers import Number
def draw_graph(image, math_func, *,
error=10,
x_scale=1, y_scale=1,
x_offset=None, y_offset=None,
color=(0, 255, 0)):
if x_offset is None:
x_offset = image.width // 2
if y_offset is None:
y_offset = image.height // 2
pxls = image.load()
for x in range(image.width):
for y in range(image.height):
output = math_func((x - x_offset) / x_scale)
if isinstance(output, Number):
if output - error <= (image.height - y - y_offset) / y_scale <= output + error:
pxls[x, y] = color
elif isinstance(output, tuple):
for out in output:
if out - error <= (image.height - y - y_offset) / y_scale <= out + error:
pxls[x, y] = color
image is a pillow Image object, math_func is a function that takes in an integer (x) and returns a number or a tuple of numbers (multiple values), error is how close the output of the function has to be to the y coordinate of the pixel in order for it to be colored, and the rest of the arguments are self explanatory. If match_func returns None, the function will ignore it.
Here is sample usage of the function (the images should show themselves at the end of the program):
from PIL import Image
from numbers import Number
from math import sqrt
def third_power(x):
return 0.01 * x**3
def one_over_x(x):
return 1 / x if x != 0 else None
def idk(x):
return sqrt(x*x - 3) if x*x > 3 else None
def draw_graph(image, math_func, *,
error=10,
x_scale=1, y_scale=1,
x_offset=None, y_offset=None,
color=(0, 255, 0)):
if x_offset is None:
x_offset = image.width // 2
if y_offset is None:
y_offset = image.height // 2
pxls = image.load()
for x in range(image.width):
for y in range(image.height):
output = math_func((x - x_offset) / x_scale)
if isinstance(output, Number):
if output - error <= (image.height - y - y_offset) / y_scale <= output + error:
pxls[x, y] = color
elif isinstance(output, tuple):
for out in output:
if out - error <= (image.height - y - y_offset) / y_scale <= out + error:
pxls[x, y] = color
img1 = Image.new("RGB", (200, 200), "black")
draw_graph(img1, third_power, error=5, x_scale=3)
draw_graph(img1, one_over_x, error=3, x_scale=100, color=(255, 0, 0))
draw_graph(img1, idk, error=1, x_scale=3, y_scale=10, color=(0, 0, 255))
img1.show()
img2 = Image.new("RGB", (2000, 2000), "black")
draw_graph(img2, lambda x: x*x, x_scale=10, y_scale=2)
img2.show()
Please comment if I made a mistake on this answer, it's 3 a.m. and I can't resist a good challenge. I hope you find this answer useful or creative.