K3D-tools / K3D-jupyter

K3D lets you create 3D plots backed by WebGL with high-level API (surfaces, isosurfaces, voxels, mesh, cloud points, vtk objects, volume renderer, colormaps, etc). The primary aim of K3D-jupyter is to be easy for use as stand alone package like matplotlib, but also to allow interoperation with existing libraries as VTK.
MIT License
917 stars 123 forks source link

Flickering colours at intermediate time steps #389

Closed MariusCausemann closed 1 year ago

MariusCausemann commented 1 year ago

Description

I want to create time-dependent figures with the colour of the points changing over time. However, the colour is only correctly displayed at the time instances that are provided in the dict of colours for each time step. Interpolated colours generated by kd3 for intermediate times are seemingly random, so the time loop shows randomly flickering colours.

What I Did

import k3d
import numpy as np
from k3d.helpers import map_colors

np.random.seed(2022)

x = np.random.randn(100,3).astype(np.float32)

plt_points = k3d.points(x,
                        color=0x528881,
                        point_size=0.2)
times = np.linspace(0, 20, 20)
plot = k3d.plot()
plot += plt_points
color_map = k3d.basic_color_maps.Jet

plt_points.positions = {str(t):x - t/5*x/np.linalg.norm(x,axis=-1)[:,np.newaxis] for t in times}
c = [map_colors(np.linalg.norm(x,axis=-1), color_map, (0,3)).astype(np.uint32)
     for x in plt_points.positions.values() ]

plt_points.colors = {str(t):c[i] for i,t in enumerate(times)}
plot.display()

K3D-1669383070505

MariusCausemann commented 1 year ago

I found a way to get around this problem: Instead of updating the colours directly, one can go via the attribute of the plot object and get the changing colours in the animation:

import k3d
import numpy as np
from k3d.helpers import map_colors

np.random.seed(2022)

x = np.random.randn(100,3).astype(np.float32)

plt_points = k3d.points(x,
                        attribute=np.linalg.norm(x,axis=-1),
                        point_size=0.2)
times = np.linspace(0, 20, 20)
plot = k3d.plot()
plot += plt_points

plt_points.positions = {str(t):x - t/5*x/np.linalg.norm(x,axis=-1)[:,np.newaxis] for t in times}
plt_points.attribute = {str(t): np.linalg.norm(x,axis=-1) for t,x in zip(times, plt_points.positions.values())}
plot.display()

My problem is solved now, so feel free to close the issue.

artur-trzesiok commented 1 year ago

@MariusCausemann good solution :). Attribute will give you option to interpolate value on colormap space rather on linear rgb. btw you discovered not supported feature in k3d - interpolation of rgb coded variable. It is doable - I will investigate that (to run also your first attempt in k3d)

I also don't like performance of animation here.

artur-trzesiok commented 1 year ago

Done :). Thanks for good feedback. Thanks to you we will have good colorhex interpolation + speed up of animation.

MariusCausemann commented 1 year ago

Nice! Thanks for fixing this and implementing the colorhex interpolation!

artur-trzesiok commented 1 year ago

@MariusCausemann thanks for finding that!