1

how can I fill the space between the x-axis and the spectral curve with the corresponding color? It only shows the colors in a band at the bottom. It would be great if the plot looks like the example: https://www.google.com/search?q=ocean+view+software&client=firefox-b-d&sxsrf=ALeKk00ddh8swDsz_7aKabw4-l1CXv3yEA:1593189268241&source=lnms&tbm=isch&sa=X&ved=2ahUKEwjByJLD9J_qAhUGwKQKHf7iBY4Q_AUoAXoECAwQAw&biw=1366&bih=654#imgrc=I3KeJE0Rq3taPM

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

def wavelength_to_rgb(wavelength, gamma=0.8):
    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=(6,6), tight_layout=True)

# set directory
df = pd.read_excel('Reflexionsspektren.xlsx', 'Tabelle1')
# data for plot1
wavelengths = df['Wavelength']
spectrum = df['Fresh']

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('Reflectance (%)')

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

plt.show()
AshlinJP
  • 363
  • 1
  • 10
  • Does this link help you ? https://matplotlib.org/2.1.1/gallery/lines_bars_and_markers/fill_between_demo.html – AshlinJP Jun 26 '20 at 16:42

1 Answers1

0

Unfortunately I could not run your code because I dont have the 'Reflexionsspektren.xlsx' file. However, a hacky solution based on this post gets the desired result I believe. I used np.vectorize to convert your wavelength_to_rgb function into an array of colors for each wavelength value on the x-axis. Using matplotlib's fill_between the spectrum is drawn between the curve and the x-axis.

import matplotlib.pyplot as plt
import numpy as np

def wavelength_to_rgb(wavelength, gamma=0.8):
    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)

if __name__ == '__main__':
    x = np.linspace(350, 780, 430)
    y = np.sin(x / 100)  # replace with your function / measured values.
    colors = np.array(np.vectorize(wavelength_to_rgb)(x))
    fig, ax = plt.subplots()
    ax.plot(x, y, color="gray")
    for i in range(len(x) - 1):
        plt.fill_between([x[i], x[i+1]], [y[i], y[i+1]], color=colors[:, i])

enter image description here

Timo
  • 493
  • 4
  • 8
  • Great, please accept the answer so others will know that this question has a solution. – Timo Jun 27 '20 at 08:09