Question:
How can you make a colormap in matplotlib to render smoothly on a display?
Let me clarify. This is the code:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as mcolors
import matplotlib as mpl
from math import trunc
def wav2RGB(Wavelength):
Gamma = 0.80
IntensityMax = 255.0
def Adjust(Color, Factor):
if Color == 0.0:
return 0.0
else:
return round(IntensityMax * (Color * Factor)**Gamma)
if 380 <= trunc(Wavelength) and trunc(Wavelength) <= 439:
Red = -(Wavelength - 440.0) / (440.0 - 380.0)
Green = 0.0
Blue = 1.0
elif 440 <= trunc(Wavelength) and trunc(Wavelength) <= 489:
Red = 0.0
Green = (Wavelength - 440.0) / (490.0 - 440.0)
Blue = 1.0
elif 490 <= trunc(Wavelength) and trunc(Wavelength) <= 509:
Red = 0.0
Green = 1.0
Blue = -(Wavelength - 510.0) / (510.0 - 490.0)
elif 510 <= trunc(Wavelength) and trunc(Wavelength) <= 579:
Red = (Wavelength - 510.0) / (580.0 - 510.0)
Green = 1.0
Blue = 0.0
elif 580 <= trunc(Wavelength) and trunc(Wavelength) <= 644:
Red = 1.0
Green = -(Wavelength - 645.0) / (645.0 - 580.0)
Blue = 0.0
elif 645 <= trunc(Wavelength) and trunc(Wavelength) <= 780:
Red = 1.0
Green = 0.0
Blue = 0.0
else:
Red = 0.0
Green = 0.0
Blue = 0.0
# Let the intensity fall off near the vision limits
if 380 <= trunc(Wavelength) and trunc(Wavelength) <= 419:
factor = 0.3 + 0.7*(Wavelength - 380.0) / (420.0 - 380.0)
elif 420 <= trunc(Wavelength) and trunc(Wavelength) <= 700:
factor = 1.0
elif 701 <= trunc(Wavelength) and trunc(Wavelength) <= 780:
factor = 0.3 + 0.7*(780.0 - Wavelength) / (780.0 - 700.0)
else:
factor = 0.0
R = Adjust(Red, factor)
G = Adjust(Green, factor)
B = Adjust(Blue, factor)
return [int(R), int(G), int(B)]
def generateColor(color):
nstep = 1000
minW = 380
maxW = 780
bandW = maxW - minW
colorTuple = ()
for i in range(nstep + 1):
wlength = minW + i * bandW / nstep
colorTuple += ((1.0 * i / nstep, wav2RGB(wlength)[color] / 255.0, wav2RGB(wlength)[color] / 255.0),)
return colorTuple
def generateGradient():
return {'red': generateColor(0),
'green': generateColor(1),
'blue': generateColor(2)}
cmaps = {}
gradient = np.linspace(0, 1, 256)
print (gradient)
gradient = np.vstack((gradient, gradient))
def plot_color_gradients(category, cmap_list):
# Create figure and adjust figure height to number of colormaps
nrows = len(cmap_list)
figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22
fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh))
fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh,
left=0.01, right=0.99)
axs[0].set_title(f'{category} colormaps', fontsize=14)
for ax, name in zip(axs, cmap_list):
if not (name == 'visibleSpec'):
ax.imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10,
transform=ax.transAxes)
else:
ax.imshow(gradient, aspect='auto', cmap=visibleSpec)
# Turn off *all* ticks & spines, not just the ones with colormaps.
for ax in axs:
ax.set_axis_off()
# Save colormap list for later.
cmaps[category] = cmap_list
visibleSpec = mcolors.LinearSegmentedColormap('visible', generateGradient())
print (f"Length of generateColor(0) is {len(generateColor(0))}")
print (f" Length is {visibleSpec.N}")
plot_color_gradients('Perceptually Uniform Sequential',
['viridis', 'plasma', 'inferno', 'magma', 'cividis','visibleSpec'])
plt.show()
This code displays the following:
The last colormap ,at the bottom, it is one custom created to show a spectrum. As you can see it has many color gradients and at that size it shows smoothly.
But if I enlarge the window on a 4k monitor here is a 1:1 crop and you can see it doesn't have smooth gradients when shown on a big monitor.
My first ideea was to make a more detailed colormap but it seems that
LinearSegmentedColormap cannot have more than 256 colors.
Any idea how to have smooth gradients with a colormap in matplotlib?