Matplotlib - 基于光谱颜色的曲线下颜色 [英] Matplotlib - color under curve based on spectral color

查看:76
本文介绍了Matplotlib - 基于光谱颜色的曲线下颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想绘制光谱图,其中曲线下方的区域将根据光的相应颜色进行着色.很像这个情节:

我试图通过使用 imshow spectral colormap绘制颜色,并使用白色的 fill_between 来模拟matplotlib中的颜色遮盖曲线上方的区域.我对结果相当满意,除了两件事:

1)我正在绘制的颜色与可见光谱不太吻合.例如,当红色为红色时,我将700 nm显示为黄色/橙色.我对某种形式的表示感到满意(例如,我认为第二个答案

解决方案

首先,您需要一个将波长作为输入并返回RGB颜色的函数.可以在

将 numpy 导入为 np导入matplotlib.pyplot作为plt导入 matplotlib.colorsdef波长_to_rgb(波长,伽马= 0.8):'''取自http://www.noah.org/wiki/Wavelength_to_RGB_in_Python这会将给定波长的光转换为近似的 RGB 颜色值.波长必须给定在380 nm至750 nm的纳米范围内(789 THz 到 400 THz).基于Dan Bruton的代码http://www.physics.sfasu.edu/astro/color/spectra.html另外,alpha值设置为0.5超出范围'''波长 = 浮点数(波长)如果波长> = 380且波长< = 750:A = 1.别的:A=0.5如果波长<380:波长= 380.如果波长>750:波长 = 750.如果波长 >= 380 且波长 <= 440:衰减= 0.3 + 0.7 *(波长-380)/(440-380)R = ((-(波长 - 440)/(440 - 380)) * 衰减) ** 伽玛G = 0.0B = (1.0 * 衰减) ** 伽玛elif 波长 >= 440 和波长 <= 490:R = 0.0G = ((波长 - 440)/(490 - 440)) ** 伽玛乙 = 1.0elif 波长 >= 490 和波长 <= 510:R = 0.0G = 1.0B =(-(波长-510)/(510-490))**伽玛elif 波长 >= 510 和波长 <= 580:R = ((波长 - 510)/(580 - 510)) ** 伽玛G = 1.0B = 0.0elif波长> = 580和波长< = 645:R = 1.0G =(-(波长-645)/(645-580))**伽玛乙 = 0.0elif 波长 >= 645 和波长 <= 750:衰减= 0.3 + 0.7 *(750-波长)/(750-645)R =(1.0 *衰减)**伽玛G = 0.0乙 = 0.0别的:R = 0.0G = 0.0乙 = 0.0返回(R,G,B,A)气候=(350,780)norm = plt.Normalize(*clim)wl = np.arange(clim [0],clim [1] +1,2)colorlist = list(zip(norm(wl),[wl中w的波长_to_rgb(w)]))spectrummap = matplotlib.colors.LinearSegmentedColormap.from_list("spectrum",colorlist)图, axs = plt.subplots(1, 1, figsize=(8,4),tight_layout=True)波长= np.linspace(200,1000,1000)光谱 = (5 + np.sin(wavelengths*0.1)**2) * np.exp(-0.00002*(wavelengths-600)**2)plt.plot(波长,光谱,颜色='暗红色')y = np.linspace(0,6,100)X,Y = np.meshgrid(波长, y)范围=(np.min(波长),np.max(波长),np.min(y),np.max(y))plt.imshow(X,clim=clim,extent=extent,cmap=spectralmap,aspect='auto')plt.xlabel('波长(nm)')plt.ylabel('强度')plt.fill_between(波长,光谱,8,颜色='w')plt.savefig('WavelengthColors.png', dpi=200)plt.show()

I would like to make a plot of of a spectrum, where the area under the curve will be shaded according the the corresponding color of the light. Much like this plot:

I have tried to emulate this in matplotlib, by using imshow with the spectral colormap to plot the colors, and a white fill_between to cover up the region above the curve. I am fairly happy with the result, except for two things:

1) The colors that I am plotting do not quite align with the visible spectrum. For example I show 700 nm as yellow/orange, when it is red. I am happy with a somewhat stylized representation (for example, I think that the accurate colors shown in the second answer here are boring), but in general, I would like to wavelengths to align with their visible colors.

2) I like how the spectrum above has the regions outside of the visible region colored with alpha<1.0. I am not sure how to achieve this.

Here is what I have so far:

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

解决方案

First of all you would need a function that takes the wavelength as input and returns an RGB color. Such a function can be found here. One may adapt it to also return an alpha value, which is smaller 1 outside the range of visible colors.

This function can be used to make create a colormap. Using a decent normalization allows to have the range of wavelengths mapped to the range between 0 and 1, such that this colormap may be used in an imshow plot.

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

这篇关于Matplotlib - 基于光谱颜色的曲线下颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆