2017-07-06 70 views
2

我想作的频谱,其中,所述曲线下的面积将根据光的相应的颜色被阴影的曲线图。就像这个图:Matplotlib - 曲线下颜色基于光谱颜色

enter image description here

我试图在matplotlib仿效这一点,通过使用imshowspectral颜色表绘制的颜色和白色fill_between来掩盖曲线以上的区域。我对结果很高兴,除了两件事情:

1),我绘制颜色不太与可见光谱一致。例如,当它呈现红色时,我会将700纳米显示为黄色/橙色。我对一个有点风格化的表示感到满意(例如,我认为第二个回答here中显示的准确颜色很无聊),但总的来说,我希望波长与其可见颜色对齐。

2)我喜欢的频谱以上如何具有alpha < 1.0着色的可见区以外的区域。我不知道如何实现这一点。

这是我到目前为止有:

所有的
import numpy as np 
import matplotlib.pyplot as plt 

fig, axs = plt.subplots(1, 1, figsize=(8,4), tight_layout=True) 

wavelengths = np.linspace(200, 1000, 1000) 
spectrum = (5 + np.sin(wavelengths*0.1)**2) * np.exp(-0.00002*(wavelengths-600)**2) 
plt.plot(wavelengths, spectrum, color='darkred') 

y = np.linspace(0, 6, 100) 
X,Y = np.meshgrid(wavelengths, y) 
X[X<400] = 400 
extent=(np.min(wavelengths), np.max(wavelengths), np.min(y), np.max(y)) 

plt.imshow(X, clim=(350,820), extent=extent, cmap=plt.get_cmap('spectral'), aspect='auto') 
plt.xlabel('Wavelength (nm)') 
plt.ylabel('Intensity') 

plt.fill_between(wavelengths, spectrum, 8, color='w') 
plt.savefig('WavelengthColors.png', dpi=200) 

plt.show() 

+0

我不明白你为什么说在链接的问题的第二个答案是枯燥的,不只是你需要什么? –

+0

我想我会更喜欢颜色地图在400纳米处变成紫色,并且有一段青色。即使这个数字比那个答案中的数字少,我认为它会更好看。 – DanHickstein

+0

我不认为你可以重写/操纵这样的CMAP,但你可以使用matplotlib的[参考](https://matplotlib.org/examples/pylab_examples/custom_cmap.html)上,并使用已知的创建一个算法就像答案中的链接。 –

回答

1

首先你需要一个函数,它的波长作为输入并返回一个RGB颜色。这样的功能可以在here找到。有人可能会调整它以返回一个alpha值,该值在可见颜色范围之外小于1。

此功能可以用来做创建的颜色表。使用正常的标准化可以将波长范围映射到0到1之间的范围,这样该色彩映射就可以在imshow图中使用。

enter image description here

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors 


def wavelength_to_rgb(wavelength, gamma=0.8): 
    ''' taken from http://www.noah.org/wiki/Wavelength_to_RGB_in_Python 
    This converts a given wavelength of light to an 
    approximate RGB color value. The wavelength must be given 
    in nanometers in the range from 380 nm through 750 nm 
    (789 THz through 400 THz). 

    Based on code by Dan Bruton 
    http://www.physics.sfasu.edu/astro/color/spectra.html 
    Additionally alpha value set to 0.5 outside range 
    ''' 
    wavelength = float(wavelength) 
    if wavelength >= 380 and wavelength <= 750: 
     A = 1. 
    else: 
     A=0.5 
    if wavelength < 380: 
     wavelength = 380. 
    if wavelength >750: 
     wavelength = 750. 
    if wavelength >= 380 and wavelength <= 440: 
     attenuation = 0.3 + 0.7 * (wavelength - 380)/(440 - 380) 
     R = ((-(wavelength - 440)/(440 - 380)) * attenuation) ** gamma 
     G = 0.0 
     B = (1.0 * attenuation) ** gamma 
    elif wavelength >= 440 and wavelength <= 490: 
     R = 0.0 
     G = ((wavelength - 440)/(490 - 440)) ** gamma 
     B = 1.0 
    elif wavelength >= 490 and wavelength <= 510: 
     R = 0.0 
     G = 1.0 
     B = (-(wavelength - 510)/(510 - 490)) ** gamma 
    elif wavelength >= 510 and wavelength <= 580: 
     R = ((wavelength - 510)/(580 - 510)) ** gamma 
     G = 1.0 
     B = 0.0 
    elif wavelength >= 580 and wavelength <= 645: 
     R = 1.0 
     G = (-(wavelength - 645)/(645 - 580)) ** gamma 
     B = 0.0 
    elif wavelength >= 645 and wavelength <= 750: 
     attenuation = 0.3 + 0.7 * (750 - wavelength)/(750 - 645) 
     R = (1.0 * attenuation) ** gamma 
     G = 0.0 
     B = 0.0 
    else: 
     R = 0.0 
     G = 0.0 
     B = 0.0 
    return (R,G,B,A) 

clim=(350,780) 
norm = plt.Normalize(*clim) 
wl = np.arange(clim[0],clim[1]+1,2) 
colorlist = zip(norm(wl),[wavelength_to_rgb(w) for w in wl]) 
spectralmap = matplotlib.colors.LinearSegmentedColormap.from_list("spectrum", colorlist) 

fig, axs = plt.subplots(1, 1, figsize=(8,4), tight_layout=True) 

wavelengths = np.linspace(200, 1000, 1000) 
spectrum = (5 + np.sin(wavelengths*0.1)**2) * np.exp(-0.00002*(wavelengths-600)**2) 
plt.plot(wavelengths, spectrum, color='darkred') 

y = np.linspace(0, 6, 100) 
X,Y = np.meshgrid(wavelengths, y) 

extent=(np.min(wavelengths), np.max(wavelengths), np.min(y), np.max(y)) 

plt.imshow(X, clim=clim, extent=extent, cmap=spectralmap, aspect='auto') 
plt.xlabel('Wavelength (nm)') 
plt.ylabel('Intensity') 

plt.fill_between(wavelengths, spectrum, 8, color='w') 
plt.savefig('WavelengthColors.png', dpi=200) 

plt.show()