Cmap in Lab Space

../../_images/anim_cmap_rot.png

Animation control:

Visualization

Frame Value

Line geometry

constant

Line position

rotation transform per frame

Line color

constant

Shading and highlighting

constant (none)

Axis coordinate

constant

Based on the static plots from the Matplotlib Colormaps and Color Space examples.

To minimize execution time, the colormap line object was constructed once, then copied for each frame construction. Rotating the copied line results in ‘stationary viewer’ perception.

import copy
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import colormaps
from matplotlib.animation import FuncAnimation
from colorspacious import cspace_converter
import s3dlib.surface as s3d
import s3dlib.cmap_utilities as cmu

#.. Cmap Line Rotation Animation

# 0. Define animation control parameters ............................

totalTime, f_domain, numFrames = 10, (0.0,1.0), 100 # time in seconds
frames=np.linspace(*f_domain, numFrames, endpoint=False)
interval = int(1000.0*totalTime/numFrames)          # milliseconds

# 1. Define function to examine ....................................

def rgb_to_labCoor(rgb):
    L,a,b = cspace_converter("sRGB1", "CAM02-UCS"  )(rgb.T).T
    return a/80,b/80,L/100

def lab_to_rgbCoor(abl) :
    Lab = np.array([ 100*abl[2],80*abl[0],80*abl[1] ])
    rgb = cspace_converter( "CAM02-UCS", "sRGB1" )(Lab.T).T
    return rgb

def cmapRGB(t,cmap):
    if isinstance(cmap,str) : cmap=colormaps[cmap]
    return cmap(t)[:,:3].T

def cmapLab(t,cmap) :
    rgb = cmapRGB(t,cmap)
    return rgb_to_labCoor(rgb)

# Setup lines and surface ........................................
lrez, lw = 5, 3
cmaps = ['viridis', 'plasma', 'inferno', 'magma', 'cividis']

labLine = None
for cmap in cmaps :
    linefunc = lambda t : cmapLab(t,cmap)
    line = s3d.ParametricLine(lrez,linefunc)
    line.map_color_from_op(lambda abl: lab_to_rgbCoor(abl))
    if labLine is None : labLine = line
    else : labLine += line
labLine.set_linewidth(lw)
labLine.transform(scale=2,translate=[0.0,0.0,-1])
labcopy = copy.copy(labLine)

# ...............................................................
rez=6

surface = s3d.CubicSurface().domain([0,1],[0,1],[0,1]).triangulate(rez)
surface.map_color_from_op(lambda xyz : xyz)
surface.map_geom_from_op(rgb_to_labCoor)
surface.transform(scale=2,translate=[0.0,0.0,-1])
surface.set_surface_alpha(0.1)
surfcopy = copy.copy(surface)

# ...............................................................
frame = .0
theta = 360*frame
surface.transform(s3d.eulerRot(theta,0)).shade(.5)
labLine.transform(s3d.eulerRot(theta,0))

# Construct figure, add surface, plot ..........................
plt.rcParams['grid.color'] = '.2'
minmax,paneColor  = (-1.1,1.1), '.05'
fig = plt.figure(figsize=(5,5), facecolor='k')
ax = plt.axes(projection='3d', facecolor='k', aspect='equal')
ax.set(xlim=minmax, ylim=minmax, zlim=minmax,
       xticks=minmax, yticks=minmax, zticks=minmax )
ax.xaxis.set_pane_color(paneColor)
ax.yaxis.set_pane_color(paneColor)
ax.zaxis.set_pane_color(paneColor)

ax.add_collection3d(surface)
ax.add_collection3d(labLine)

fig.tight_layout(pad=0)
#plt.show()

# 4. Animation ======================================================

def update_fig(frame):
    global surface
    global labLine

    theta = 360*frame
    surface.remove()
    labLine.remove()
    surface = copy.copy(surfcopy)
    labLine = copy.copy(labcopy)
    surface.transform(s3d.eulerRot(theta,0)).shade(.5)
    labLine.transform(s3d.eulerRot(theta,0))

    ax.add_collection3d(surface)
    ax.add_collection3d(labLine)
    return

anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('cmap_rot.html',writer='html')

msg = "saved {} frames, values: [{:.3f} to {:.3f}] @ {} milliseconds/frane"
print(msg.format(numFrames,np.min(frames),np.max(frames),interval))