如何在 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中画线了
我不知道如何在 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中画线了