{ "cells": [ { "cell_type": "markdown", "id": "3223b870", "metadata": {}, "source": [ "# Color Wheel Tutorial\n", "\n", "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)" ] }, { "cell_type": "code", "execution_count": null, "id": "747f5632", "metadata": {}, "outputs": [], "source": [ "from manim import *\n", "from PIL import Image\n", "import colorsys\n", "import math\n", "from colorutils import hsv_to_hex,hex_to_hsv #pip install colorutils" ] }, { "cell_type": "code", "execution_count": null, "id": "869a8282", "metadata": {}, "outputs": [], "source": [ "size=490\n", "im = Image.new(\"RGB\", (size,size))\n", "radius = min(im.size)/2.0\n", "cx, cy = im.size[0]/2, im.size[1]/2\n", "pix = im.load()\n", "\n", "for x in range(im.width):\n", " for y in range(im.height):\n", " rx = x - cx\n", " ry = y - cy\n", " s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius\n", " if s <= 1.0:\n", " h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0\n", " rgb = colorsys.hsv_to_rgb(h, s, 1)\n", " pix[x,y] = tuple([int(round(c*255.0)) for c in rgb])\n", "hsv_hue_sat = im\n", "display(hsv_hue_sat)" ] }, { "cell_type": "code", "execution_count": null, "id": "5d60694f", "metadata": {}, "outputs": [], "source": [ "im = Image.new(\"RGB\", (size,size))\n", "radius = min(im.size)/2.0\n", "cx, cy = im.size[0]/2, im.size[1]/2\n", "pix = im.load()\n", "\n", "for x in range(im.width):\n", " for y in range(im.height):\n", " rx = x - cx\n", " ry = y - cy\n", " s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius\n", " if s <= 1.0:\n", " h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0\n", " rgb = colorsys.hsv_to_rgb(0, s, 1 )\n", " rgb = [np.mean(rgb)]*3\n", " pix[x,y] = tuple([int(255-round(c*255.0)) for c in rgb])\n", "hsv_value = im\n", "display(hsv_value)" ] }, { "cell_type": "code", "execution_count": null, "id": "8c5fa279", "metadata": {}, "outputs": [], "source": [ "class ColorWheels(Group):\n", " def __init__(self, **kwargs):\n", " Group.__init__(self, **kwargs)\n", " im_hue = ImageMobject(hsv_hue_sat).set_z_index(-5)\n", " im_val = ImageMobject(hsv_value).set_z_index(-5)\n", " # im_hue = Circle(radius=1.5).set_style(fill_color=WHITE, fill_opacity=1).set_z_index(-5)\n", " # im_val = Circle(radius=1.5).set_style(fill_color=WHITE, fill_opacity=1).set_z_index(-5)\n", " self.radius = im_hue.height/2\n", " self.add(im_hue, im_val)\n", " Group(*self.submobjects).arrange(DOWN, SMALL_BUFF*1.3).to_edge(RIGHT)\n", " t1= Text(\"Hue and Saturation\").scale(0.3)\n", " t1.next_to(im_hue, UP, buff=SMALL_BUFF).rotate(35*DEGREES, about_point=im_hue.get_center())\n", " self.add(t1)\n", " t2= Text(\"Value\").scale(0.3)\n", " t2.next_to(im_val, UP, buff=SMALL_BUFF).rotate(35*DEGREES, about_point=im_val.get_center())\n", " self.add(t2)\n", " global CENTER_HUE , CENTER_VAL\n", " CENTER_HUE = im_hue.get_center()\n", " CENTER_VAL = im_val.get_center()" ] }, { "cell_type": "code", "execution_count": null, "id": "7058d6c2", "metadata": {}, "outputs": [], "source": [ "class HueValSlider(Group):\n", " def __init__(self, wheels, h, s, v,**kwargs):\n", " hue_tracker= ValueTracker(h)\n", " sat_tracker= ValueTracker(s)\n", " val_tracker= ValueTracker(v)\n", " self.hue_tracker= hue_tracker\n", " self.sat_tracker= sat_tracker\n", " self.val_tracker= val_tracker\n", "\n", " Group.__init__(self, **kwargs)\n", " hue_dot = Dot(CENTER_HUE+LEFT).set_color(BLACK).scale(0.8).set_z_index(1)\n", " hue_line = Line(CENTER_HUE, hue_dot.get_center()).set_color(BLACK).set_stroke(width=2)\n", " self.hue_line =hue_line\n", " hue_circ= Circle().set_color(BLACK).scale(0.08).move_to(hue_dot.get_center())\n", " 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])))\n", " 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()))))\n", " hue_line.add_updater(lambda x: x.put_start_and_end_on(CENTER_HUE, hue_dot.get_center()))\n", " \n", " hue_circ.add_updater(lambda x: x.move_to(hue_dot.get_center()))\n", " self.add(hue_dot, hue_circ, hue_line)\n", "\n", " val_dot = Dot(CENTER_VAL+LEFT).set_color(BLACK).scale(0.8).set_z_index(1)\n", " val_line = Line(CENTER_VAL, val_dot.get_center()).set_color(BLACK).set_stroke(width=2)\n", " val_circ= Circle().set_color(BLACK).scale(0.08).move_to(val_dot.get_center())\n", " 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])))\n", " 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()))))\n", " val_line.add_updater(lambda x: x.put_start_and_end_on(CENTER_VAL, val_dot.get_center()))\n", " val_circ.add_updater(lambda x: x.move_to(val_dot.get_center()))\n", " self.add(val_dot, val_circ, val_line)" ] }, { "cell_type": "code", "execution_count": null, "id": "51c28055", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qm --disable_caching Idea3\n", "\n", "class Idea3(Scene):\n", " def construct(self):\n", " wheels = ColorWheels()\n", " self.add(wheels)\n", " t1= Dot().scale(4)\n", " t2= Dot().scale(4)\n", " \n", " t3 = Dot().scale(4)\n", " gr = VGroup(t1,t2,t3).arrange(DOWN)\n", " self.add(gr)\n", " \n", " t1.add_updater(lambda x: x.set_color(hsv_to_hex((huevals1.hue_tracker.get_value()%360, huevals1.sat_tracker.get_value(),1))))\n", " t2.add_updater(lambda x: x.set_color(hsv_to_hex((huevals2.hue_tracker.get_value()%360, huevals2.sat_tracker.get_value(),1))))\n", " t3.add_updater(lambda x: x.set_color(hsv_to_hex((huevals3.hue_tracker.get_value()%360, huevals3.sat_tracker.get_value(),1))))\n", " \n", " \n", " huevals1=HueValSlider(wheels,0,1,1)\n", " huevals2=HueValSlider(wheels,120,1,1)\n", " huevals3=HueValSlider(wheels,240,1,1)\n", " \n", " \n", " \n", " self.add(huevals1)\n", " self.add(huevals2)\n", " self.add(huevals3)\n", " hues_all_tracker = ValueTracker(0)\n", " \n", " self.add(hues_all_tracker)\n", " self.add(huevals1.hue_tracker)\n", " self.add(huevals2.hue_tracker)\n", " self.add(huevals3.hue_tracker)\n", "\n", " huevals1.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))\n", " huevals2.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))\n", " huevals3.hue_tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt*30))\n", "\n", " self.wait(3)\n", " \n", " self.play(\n", " huevals1.sat_tracker.animate.increment_value(-0.2),\n", " huevals2.sat_tracker.animate.increment_value(-0.2),\n", " huevals3.sat_tracker.animate.increment_value(-0.2),\n", " )\n", " self.wait(1)\n", " self.play(\n", " huevals1.val_tracker.animate.increment_value(-0.2),\n", " huevals2.val_tracker.animate.increment_value(-0.2),\n", " huevals3.val_tracker.animate.increment_value(-0.2),\n", " )\n", " self.wait(1)" ] }, { "cell_type": "code", "execution_count": null, "id": "528d18b3-239f-48ef-ac1f-1b4f2524a7d7", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.5" } }, "nbformat": 4, "nbformat_minor": 5 }