相位角图中使用的无视觉畸变的循环彩色地图?

2024-09-27 04:20:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一个好的圆形/循环颜色映射来表示相位角信息(其中值限制在范围[0,2π],其中0和2π表示相同的相位角)。

背景:我想通过绘制整个系统振荡的功率谱密度和相对相位信息来可视化正常模式。

我承认以前我用“彩虹”彩色地图绘制功率图,用“hsv”彩色地图绘制相位图(见[1])。然而,彩虹彩色地图的使用是极不鼓励的,因为它缺乏知觉线性和排序[2][3]。所以我切换到了“coolwarm”彩色地图的功率图,我很喜欢。不幸的是,“hsv”彩色地图似乎引入了与“彩虹”地图相同的视觉扭曲(而且它也不太符合“coolwarm”地图,因为相比之下它看起来有点丑陋和浮华)。

有没有人对我可以用来绘制相位图的循环彩色地图有很好的建议?

要求:

  • 它需要是圆形的,以便0和2π的值用相同的颜色表示。

  • 它不应该引入任何视觉扭曲;特别是,它应该是感知线性的(“hsv”彩色地图似乎不是这样)。我不认为感知排序对相位信息有这么大的影响,但它当然不会造成任何伤害。

  • 当与“coolwarm”颜色映射结合时,它应该具有视觉吸引力。不过,我并没有对“coolwarm”一窍不通,如果还有另一对彩色地图可以显示振幅和相位信息,我很乐意考虑其他选择。

如果colormap可在matplotlib中使用(或可以轻松创建),则可获得额外积分。

非常感谢您的建议!

[1]http://matplotlib.org/examples/color/colormaps_reference.html

[2]http://www.renci.org/~borland/pdfs/RainbowColorMap_VisViewpoints.pdf

[3]http://medvis.org/2012/08/21/rainbow-colormaps-what-are-they-good-for-absolutely-nothing/


Tags: org信息http排序颜色地图绘制线性
3条回答

matplotlib version 3.0开始,有内置的循环perceptually uniform colormaps。好的,目前只有一个颜色映射,但是有两个选择开始和结束,即^{} and ^{}

一个简短的例子来演示它们的外观:

import matplotlib.pyplot as plt
import numpy as np

# example data: argument of complex numbers around 0
N = 100
re,im = np.mgrid[-1:1:100j, -1:1:100j]
angle = np.angle(re + 1j*im)

cmaps = 'twilight', 'twilight_shifted'
fig,axs = plt.subplots(ncols=len(cmaps), figsize=(9.5,5.5))
for cmap,ax in zip(cmaps,axs):
    cf = ax.pcolormesh(re, im, angle, shading='gouraud', cmap=cmap)
    ax.set_title(cmap)
    ax.set_xlabel(r'$\operatorname{Re} z$')
    ax.set_ylabel(r'$\operatorname{Im} z$')
    ax.axis('scaled')

    cb = plt.colorbar(cf, ax=ax, orientation='horizontal')
    cb.set_label(r'$\operatorname{Arg} z$')
fig.tight_layout()

上图为:

twilight and twilight_shifted colormaps in action

这些全新的彩色地图是对现有的感知一致(顺序)彩色地图集合的一个惊人的补充,即viridisplasmainfernomagmacividis(最后一个是a new addition in 2.2,它不仅感知一致,而且对色盲友好,但它应该尽可能接近色盲和非色盲的人)。

您可以尝试"husl" system,它类似于hls/hsv,但具有更好的视觉特性。它在seabornstandalone package中可用。

下面是一个简单的例子:

import numpy as np
from numpy import sin, cos, pi
import matplotlib.pyplot as plt
import seaborn as sns

n = 314
theta = np.linspace(0, 2 * pi, n)

x = cos(theta)
y = sin(theta)

f = plt.figure(figsize=(10, 5))
with sns.color_palette("husl", n):
    ax = f.add_subplot(121)
    ax.plot([np.zeros_like(x), x], [np.zeros_like(y), y], lw=3)
    ax.set_axis_off()
    ax.set_title("HUSL space")

with sns.color_palette("hls", n):
    ax = f.add_subplot(122)
    ax.plot([np.zeros_like(x), x], [np.zeros_like(y), y], lw=3)
    ax.set_axis_off()
    ax.set_title("HLS space")

f.tight_layout()

enter image description here

编辑:Matplotlib现在有很好的循环颜色映射,请参阅下面@andras deak的答案。他们使用类似于这个答案的颜色映射方法,但是在亮度上平滑边缘。

“色调外壳”颜色映射的问题是,从中读取角度是不直观的。因此,我建议你自己制作彩色地图。以下是一些可能性:

  • 对于线性分段颜色映射,我们定义了一些颜色。然后,颜色映射是颜色之间的线性插值。这有视觉扭曲。
  • 对于亮度HSLUV map,我们使用HUSL(“HSLUV”)空间,但是我们使用两种颜色和亮度通道,而不仅仅是色调通道。这个有distortions in the chroma,但有明亮的颜色。
  • 在亮度HPLUV图中,我们使用HPLUV颜色空间(根据@mwaskom的评论)。这是唯一一种真正没有视觉扭曲的方法,但是颜色是不饱和的 这就是他们的样子:

colormap with simple function

在我们的自定义颜色图中,白色代表0,蓝色代表1i,等等。 在右上角,我们可以看到色调外壳图进行比较。在这里,颜色角度指定是随机的。

enter image description here

另外,当绘制一个更复杂的函数时,当使用我们的一个颜色映射时,可以直接读取结果的阶段。

下面是情节的代码:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as col
import seaborn as sns
import hsluv # install via pip
import scipy.special # just for the example function

##### generate custom colormaps
def make_segmented_cmap(): 
    white = '#ffffff'
    black = '#000000'
    red = '#ff0000'
    blue = '#0000ff'
    anglemap = col.LinearSegmentedColormap.from_list(
        'anglemap', [black, red, white, blue, black], N=256, gamma=1)
    return anglemap

def make_anglemap( N = 256, use_hpl = True ):
    h = np.ones(N) # hue
    h[:N//2] = 11.6 # red 
    h[N//2:] = 258.6 # blue
    s = 100 # saturation
    l = np.linspace(0, 100, N//2) # luminosity
    l = np.hstack( (l,l[::-1] ) )

    colorlist = np.zeros((N,3))
    for ii in range(N):
        if use_hpl:
            colorlist[ii,:] = hsluv.hpluv_to_rgb( (h[ii], s, l[ii]) )
        else:
            colorlist[ii,:] = hsluv.hsluv_to_rgb( (h[ii], s, l[ii]) )
    colorlist[colorlist > 1] = 1 # correct numeric errors
    colorlist[colorlist < 0] = 0 
    return col.ListedColormap( colorlist )

N = 256
segmented_cmap = make_segmented_cmap()
flat_huslmap = col.ListedColormap(sns.color_palette('husl',N))
hsluv_anglemap = make_anglemap( use_hpl = False )
hpluv_anglemap = make_anglemap( use_hpl = True )

##### generate data grid
x = np.linspace(-2,2,N)
y = np.linspace(-2,2,N)
z = np.zeros((len(y),len(x))) # make cartesian grid
for ii in range(len(y)): 
    z[ii] = np.arctan2(y[ii],x) # simple angular function
    z[ii] = np.angle(scipy.special.gamma(x+1j*y[ii])) # some complex function

##### plot with different colormaps
fig = plt.figure(1)
fig.clf()
colormapnames = ['segmented map', 'hue-HUSL', 'lum-HSLUV', 'lum-HPLUV']
colormaps = [segmented_cmap, flat_huslmap, hsluv_anglemap, hpluv_anglemap]
for ii, cm in enumerate(colormaps):
    ax = fig.add_subplot(2, 2, ii+1)
    pmesh = ax.pcolormesh(x, y, z/np.pi, 
        cmap = cm, vmin=-1, vmax=1)
    plt.axis([x.min(), x.max(), y.min(), y.max()])
    cbar = fig.colorbar(pmesh)
    cbar.ax.set_ylabel('Phase [pi]')
    ax.set_title( colormapnames[ii] )
plt.show()

相关问题 更多 >

    热门问题