Color Wheel Tutorial#
In this notebook, you will learn how to create a color picker with a moving wheel in manim (scroll to the end to see the result)
[1]:
from manim import *
config.media_embed = True
from PIL import Image
import colorsys
import math
from colorutils import hsv_to_hex,hex_to_hsv #pip install colorutils
Manim Community v0.17.3
[2]:
size=490
im = Image.new("RGB", (size,size))
radius = min(im.size)/2.0
cx, cy = im.size[0]/2, im.size[1]/2
pix = im.load()
for x in range(im.width):
for y in range(im.height):
rx = x - cx
ry = y - cy
s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius
if s <= 1.0:
h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0
rgb = colorsys.hsv_to_rgb(h, s, 1)
pix[x,y] = tuple([int(round(c*255.0)) for c in rgb])
hsv_hue_sat = im
display(hsv_hue_sat)
[3]:
im = Image.new("RGB", (size,size))
radius = min(im.size)/2.0
cx, cy = im.size[0]/2, im.size[1]/2
pix = im.load()
for x in range(im.width):
for y in range(im.height):
rx = x - cx
ry = y - cy
s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius
if s <= 1.0:
h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0
rgb = colorsys.hsv_to_rgb(0, s, 1 )
rgb = [np.mean(rgb)]*3
pix[x,y] = tuple([int(255-round(c*255.0)) for c in rgb])
hsv_value = im
display(hsv_value)
[4]:
class ColorWheels(Group):
def __init__(self, **kwargs):
Group.__init__(self, **kwargs)
im_hue = ImageMobject(hsv_hue_sat).set_z_index(-5)
im_val = ImageMobject(hsv_value).set_z_index(-5)
# im_hue = Circle(radius=1.5).set_style(fill_color=WHITE, fill_opacity=1).set_z_index(-5)
# im_val = Circle(radius=1.5).set_style(fill_color=WHITE, fill_opacity=1).set_z_index(-5)
self.radius = im_hue.height/2
self.add(im_hue, im_val)
Group(*self.submobjects).arrange(DOWN, SMALL_BUFF*1.3).to_edge(RIGHT)
t1= Text("Hue and Saturation").scale(0.3)
t1.next_to(im_hue, UP, buff=SMALL_BUFF).rotate(35*DEGREES, about_point=im_hue.get_center())
self.add(t1)
t2= Text("Value").scale(0.3)
t2.next_to(im_val, UP, buff=SMALL_BUFF).rotate(35*DEGREES, about_point=im_val.get_center())
self.add(t2)
global CENTER_HUE , CENTER_VAL
CENTER_HUE = im_hue.get_center()
CENTER_VAL = im_val.get_center()
[5]:
class HueValSlider(Group):
def __init__(self, wheels, h, s, v,**kwargs):
hue_tracker= ValueTracker(h)
sat_tracker= ValueTracker(s)
val_tracker= ValueTracker(v)
self.hue_tracker= hue_tracker
self.sat_tracker= sat_tracker
self.val_tracker= val_tracker
Group.__init__(self, **kwargs)
hue_dot = Dot(CENTER_HUE+LEFT).set_color(BLACK).scale(0.8).set_z_index(1)
hue_line = Line(CENTER_HUE, hue_dot.get_center()).set_color(BLACK).set_stroke(width=2)
self.hue_line =hue_line
hue_circ= Circle().set_color(BLACK).scale(0.08).move_to(hue_dot.get_center())
hue_dot.add_updater(lambda x: x.move_to(CENTER_HUE+wheels.radius*sat_tracker.get_value()* np.array([-np.cos(hue_tracker.get_value()*DEGREES),np.sin(hue_tracker.get_value()*DEGREES),0])))
hue_dot.add_updater(lambda x: x.set_color(hsv_to_hex((hue_tracker.get_value()%360, sat_tracker.get_value(),val_tracker.get_value()))))
hue_line.add_updater(lambda x: x.put_start_and_end_on(CENTER_HUE, hue_dot.get_center()))
hue_circ.add_updater(lambda x: x.move_to(hue_dot.get_center()))
self.add(hue_dot, hue_circ, hue_line)
val_dot = Dot(CENTER_VAL+LEFT).set_color(BLACK).scale(0.8).set_z_index(1)
val_line = Line(CENTER_VAL, val_dot.get_center()).set_color(BLACK).set_stroke(width=2)
val_circ= Circle().set_color(BLACK).scale(0.08).move_to(val_dot.get_center())
val_dot.add_updater(lambda x: x.move_to(CENTER_VAL+wheels.radius*val_tracker.get_value()* np.array([-np.cos(hue_tracker.get_value()*DEGREES),np.sin(hue_tracker.get_value()*DEGREES),0])))
val_dot.add_updater(lambda x: x.set_color(hsv_to_hex((hue_tracker.get_value()%360, sat_tracker.get_value(),val_tracker.get_value()))))
val_line.add_updater(lambda x: x.put_start_and_end_on(CENTER_VAL, val_dot.get_center()))
val_circ.add_updater(lambda x: x.move_to(val_dot.get_center()))
self.add(val_dot, val_circ, val_line)
[6]:
%%manim -v WARNING -qm --disable_caching Idea3
class Idea3(Scene):
def construct(self):
wheels = ColorWheels()
self.add(wheels)
t1= Dot().scale(4)
t2= Dot().scale(4)
t3 = Dot().scale(4)
gr = VGroup(t1,t2,t3).arrange(DOWN)
self.add(gr)
t1.add_updater(lambda x: x.set_color(hsv_to_hex((huevals1.hue_tracker.get_value()%360, huevals1.sat_tracker.get_value(),1))))
t2.add_updater(lambda x: x.set_color(hsv_to_hex((huevals2.hue_tracker.get_value()%360, huevals2.sat_tracker.get_value(),1))))
t3.add_updater(lambda x: x.set_color(hsv_to_hex((huevals3.hue_tracker.get_value()%360, huevals3.sat_tracker.get_value(),1))))
huevals1=HueValSlider(wheels,0,1,1)
huevals2=HueValSlider(wheels,120,1,1)
huevals3=HueValSlider(wheels,240,1,1)
self.add(huevals1)
self.add(huevals2)
self.add(huevals3)
hues_all_tracker = ValueTracker(0)
self.add(hues_all_tracker)
self.add(huevals1.hue_tracker)
self.add(huevals2.hue_tracker)
self.add(huevals3.hue_tracker)
huevals1.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))
huevals2.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))
huevals3.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))
self.wait(3)
self.play(
huevals1.sat_tracker.animate.increment_value(-0.2),
huevals2.sat_tracker.animate.increment_value(-0.2),
huevals3.sat_tracker.animate.increment_value(-0.2),
)
self.wait(1)
self.play(
huevals1.val_tracker.animate.increment_value(-0.2),
huevals2.val_tracker.animate.increment_value(-0.2),
huevals3.val_tracker.animate.increment_value(-0.2),
)
self.wait(1)
[ ]: