【问题标题】:matplotlib imshow complex 2D arraymatplotlib imshow 复杂的二维数组
【发布时间】:2013-06-11 12:25:57
【问题描述】:

有没有什么好的方法可以在 mathplotlib 中绘制二维复数数组作为图像?

将复数的幅度映射为“亮度”或“饱和度”并将相位映射为“色调”非常有意义(无论如何,色调只不过是 RBG 颜色空间中的相位)。 http://en.wikipedia.org/wiki/HSL_and_HSV

但据我所知,imshow 只接受标量值,然后使用一些色标进行映射。没有什么比绘制真正的 RGB 图片更好的了?

我认为实现一个版本会很容易,它接受 3 个浮点数的 2D 元组(向量)数组或形状为 [:,:,3] 的浮点数 ndarray。我想这通常是有用的功能。它对于绘制真实的 RGB 彩色图像也很有用,例如从 OpenCL 输出的纹理

【问题讨论】:

标签: matplotlib multidimensional-array complex-numbers


【解决方案1】:

这与@Hooked 代码几乎相同,但速度要快得多。

import numpy as np
from numpy import pi
import pylab as plt
from colorsys import hls_to_rgb

def colorize(z):
    r = np.abs(z)
    arg = np.angle(z) 

    h = (arg + pi)  / (2 * pi) + 0.5
    l = 1.0 - 1.0/(1.0 + r**0.3)
    s = 0.8

    c = np.vectorize(hls_to_rgb) (h,l,s) # --> tuple
    c = np.array(c)  # -->  array of (3,n,m) shape, but need (n,m,3)
    c = c.swapaxes(0,2) 
    return c

N=1000
x,y = np.ogrid[-5:5:N*1j, -5:5:N*1j]
z = x + 1j*y

w = 1/(z+1j)**2 + 1/(z-2)**2
img = colorize(w)
plt.imshow(img)
plt.show()

【讨论】:

  • 当您执行 c.swapaxes(0,2) 时,您正在改变原始图像的方向。之后我需要一个额外的交换轴(0,1)才能正确渲染我的图像。但是,我使用了 meshgrid 而不是 ogrid,因为我不知道后者是如何工作的;也许这有所作为?
  • @Adarain 或者我们将第 15 行从 c = c.swapaxes(0,2) 更改为 c = c.transpose(1,2,0)
【解决方案2】:

改编 mpmath 中的绘图代码,您可以使用 numpy 和 matplotlib 绘制一个 numpy 数组即使您不知道原始函数。如果你知道函数,see my original answer 使用 mpmath.cplot

from colorsys import hls_to_rgb

def colorize(z):
    n,m = z.shape
    c = np.zeros((n,m,3))
    c[np.isinf(z)] = (1.0, 1.0, 1.0)
    c[np.isnan(z)] = (0.5, 0.5, 0.5)

    idx = ~(np.isinf(z) + np.isnan(z))
    A = (np.angle(z[idx]) + np.pi) / (2*np.pi)
    A = (A + 0.5) % 1.0
    B = 1.0 - 1.0/(1.0+abs(z[idx])**0.3)
    c[idx] = [hls_to_rgb(a, b, 0.8) for a,b in zip(A,B)]
    return c

从这里,您可以绘制任意复杂的 numpy 数组:

N = 1000
A = np.zeros((N,N),dtype='complex')
axis_x = np.linspace(-5,5,N)
axis_y = np.linspace(-5,5,N)
X,Y = np.meshgrid(axis_x,axis_y)
Z = X + Y*1j

A = 1/(Z+1j)**2 + 1/(Z-2)**2

# Plot the array "A" using colorize
import pylab as plt
plt.imshow(colorize(A), interpolation='none',extent=(-5,5,-5,5))
plt.show()

【讨论】:

  • 非常感谢!它很慢,所以如果有这样的函数直接硬编码 numpy 会更好(我的意思是与 numpy 中的其他数组操作相同的方式加速 - 无需通过 python 循环遍历数组)。但重要的是它有效。
  • @ProkopHapala 实际上大部分工作用 numpy 完成的,除了对 hls_to_rgb 的调用,您可能会对其进行矢量化。您可以通过更改点数N 使其快很多,速度应该与N^2 成正比。
【解决方案3】:

mpmath 使用matplotlib 生成复平面的精美图像。在复平面上,您通常关心极点,因此函数的参数给出颜色(因此极点将形成螺旋形)。值极大或极小的区域由饱和度控制。来自文档:

默认情况下,复杂参数(相位)显示为颜色(色调)和 幅度显示为亮度。您还可以提供一个 自定义颜色函数(color)。这个函数应该采取 复数作为输入并返回一个包含 RGB 3 元组 在 0.0-1.0 范围内浮动。

例子:

import mpmath
mpmath.cplot(mpmath.gamma, points=100000)

另一个显示zeta function、小零和critical strip的示例:

import mpmath
mpmath.cplot(mpmath.zeta, [-45,5],[-25,25], points=100000)

【讨论】:

  • 这看起来不错,但它只是用于绘制我知道分析处方的函数。这不是我的情况。我需要一些东西来绘制带有离散采样的复杂数据,这些数据是从文本文件中读取并存储在 2D narray 中的。对于这些数据,我没有明确的功能处方,可以在任何时候进行采样。
【解决方案4】:

您可以使用matplotlib.colors.hsv_to_rgb 代替colorsys.hls_to_rgbmatplotlib 函数快了大约 10 倍!查看以下结果:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
import time

def Complex2HSV(z, rmin, rmax, hue_start=90):
    # get amplidude of z and limit to [rmin, rmax]
    amp = np.abs(z)
    amp = np.where(amp < rmin, rmin, amp)
    amp = np.where(amp > rmax, rmax, amp)
    ph = np.angle(z, deg=1) + hue_start
    # HSV are values in range [0,1]
    h = (ph % 360) / 360
    s = 0.85 * np.ones_like(h)
    v = (amp -rmin) / (rmax - rmin)
    return hsv_to_rgb(np.dstack((h,s,v)))

这是@nadapez 挑选答案的方法:

from colorsys import hls_to_rgb
def colorize(z):
    r = np.abs(z)
    arg = np.angle(z) 

    h = (arg + np.pi)  / (2 * np.pi) + 0.5
    l = 1.0 - 1.0/(1.0 + r**0.3)
    s = 0.8

    c = np.vectorize(hls_to_rgb) (h,l,s) # --> tuple
    c = np.array(c)  # -->  array of (3,n,m) shape, but need (n,m,3)
    c = c.swapaxes(0,2) 
    return c

用 1024*1024 2darray 测试两种方法的结果:

N=1024
x, y = np.ogrid[-4:4:N*1j, -4:4:N*1j]
z = x + 1j*y

t0 = time.time()
img = Complex2HSV(z, 0, 4)
t1 = time.time()
print "Complex2HSV method: "+ str (t1 - t0) +" s"

t0 = time.time()
img = colorize(z)
t1 = time.time()
print "colorize method: "+ str (t1 - t0) +" s"

我的旧笔记本电脑上的这个结果:

Complex2HSV method: 0.250999927521 s
colorize method: 2.03200006485 s

【讨论】:

    【解决方案5】:

    你也可以使用 PIL.image 来转换它

    import PIL.Image
    
    def colorize(z):
      z = Zxx
      n,m = z.shape
    
      A = (np.angle(z) + np.pi) / (2*np.pi)
      A = (A + 0.5) % 1.0 * 255
      B = 1.0 - 1.0/(1.0+abs(z)**0.3)
      B = abs(z)/ z.max() * 255
      H = np.ones_like(B)
      image = PIL.Image.fromarray(np.stack((A, B, np.full_like(A, 255)), axis=-1).astype(np.uint8), "HSV") # HSV has range 0..255 for all channels
      image = image.convert(mode="RGB")
    
      return np.array(image)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 2016-03-13
      • 2014-04-27
      • 1970-01-01
      相关资源
      最近更新 更多