如何在 python 中绘制映射

How to plot Mappings in python

我不知道如何在 python 中绘制映射,我所说的映射是指非线性映射,对于线性映射,已经有 GeoGebra 您可以使用它来可视化它们,但是我找不到网站甚至 python 脚本来可视化非线性地图,要理解我所说的非线性地图的意思,这里是这张图片

来自3blue1brown,实际上是复函数f(z)=z**2的图,但你可以很容易地将它转换成地图,即F(x,y)=(x**2-y**2,2*x*y)

所以我的问题是,我应该使用什么库来在 python 中绘制这些东西?

注意:这绝不是一个好的解决方案,我写这个答案是为了让你有一个答案,无论好坏

我的方法是创建一个图像并将每个像素视为图形上的一个点,方法是将像素的 x 坐标插入一个函数,该函数 returns 一个数字根据 y 坐标进行检查像素。如果函数的结果等于 y 坐标,则像素的颜色发生变化。我添加了一些选项来自定义图表的外观。这是函数(它只是一个原型意思,并没有发挥其潜在的效率,如果你喜欢这种方法我可以改进代码):

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 是一个枕头图像对象,math_func 是一个接受整数 (x) 和 returns 数字或数字元组(多个值)的函数,错误是函数的输出必须与像素的 y 坐标有多接近才能对其进行着色,其余参数不言自明。如果match_func returns None,函数会忽略它。

下面是该函数的示例用法(图像应在程序末尾自行显示):

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()

如果我在这个答案上有错误,请发表评论,它是 3 a.m。我无法抗拒好的挑战。我希望你觉得这个答案有用或有创意。

您可能想看看 Sympy's plotting capabilities。它使用 Matplotlib 作为后端。它仍然需要一些工作,因为您需要明确指定每一行:

 import sympy as sy

# Create symbolic function Fz = (x + i*y)**2:
x, y, t = sy.symbols("x, y, t", real=True)
z = x + sy.I * y
Fz = sy.expand(z**2)

# Create expressions for the grid lines:
x_lines, y_lines = [], []
for g_ in range(-5, 6):
    Fz_y, Fz_x = Fz.subs({x: g_/2, y: t}), Fz.subs({x: t, y: g_/2})
    x_lines.append((sy.re(Fz_x), sy.im(Fz_x)))
    y_lines.append((sy.re(Fz_y), sy.im(Fz_y)))

# Make the plot:
plt0 = sy.plot_parametric(*(x_lines+y_lines), (t, -5, 5), show=False,
                          xlim=(-3, 3), ylim=(-4, 4), axis_center=(-3, -4),
                          xlabel="Re", ylabel="Im")

# Adapt color for each line separately:
for c_, p_ in enumerate(plt0):
    p_.line_color = 'blue' if c_ < len(x_lines) else 'red'

plt0.show()  # do the drawing

# Access matplotlib backend (works only in interactive IPython shell):
ax = plt0._backend.ax[0]  # get matplotlib axis
ax.grid(True)

它给出:

或者,您可以使用 lambify() 将 Sympy 表达式转换为 Numpy 函数,例如:

Fz_np = sy.lambdify((x, y), Fz)
print(f"Fz(1, 2) = {Fz_np(1, 2)}")

然后就可以用传统的方式在Matplotlib中画线了