mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Support VDict init from python dict of mobjects (#316)
* Support VDict init from python dict of mobjects * Small style change * Formatting using black * Rework VDict to emulate init of python dict * Update comment * Add a few tests * Update manim/mobject/types/vectorized_mobject.py * Update docs * Add few more tests, raise TypeError instead of Exception * Raise KeyError instead of Exception when key is not in the VDcit * Remove old comment Co-authored-by: Leo Torres <dleonardotn@gmail.com>
This commit is contained in:
parent
5054700109
commit
c19a06db24
4 changed files with 118 additions and 47 deletions
|
|
@ -118,14 +118,14 @@ class UpdatersExample(Scene):
|
|||
self.wait()
|
||||
|
||||
|
||||
class VDictTest(Scene):
|
||||
class VDictExample(Scene):
|
||||
def construct(self):
|
||||
square = Square().set_color(RED)
|
||||
circle = Circle().set_color(YELLOW).next_to(square, UP)
|
||||
|
||||
# create dict from list of tuples each having key-mobject pair
|
||||
pairs = [("s", square), ("c", circle)]
|
||||
my_dict = VDict(*pairs, show_keys=True)
|
||||
my_dict = VDict(pairs, show_keys=True)
|
||||
|
||||
# display it just like a VGroup
|
||||
self.play(ShowCreation(my_dict))
|
||||
|
|
@ -133,8 +133,9 @@ class VDictTest(Scene):
|
|||
|
||||
text = TextMobject("Some text").set_color(GREEN).next_to(square, DOWN)
|
||||
|
||||
# add like a VGroup
|
||||
my_dict.add(("t", text))
|
||||
# add a key-value pair by wrapping it in a single-element list of tuple
|
||||
# after attrs branch is merged, it will be easier like `.add(t=text)`
|
||||
my_dict.add([("t", text)])
|
||||
self.wait()
|
||||
|
||||
rect = Rectangle().next_to(text, DOWN)
|
||||
|
|
@ -150,7 +151,7 @@ class VDictTest(Scene):
|
|||
my_dict["t"] = TextMobject("Some other text").set_color(BLUE)
|
||||
self.wait()
|
||||
|
||||
# remove submojects by key
|
||||
# remove submoject by key
|
||||
my_dict.remove("t")
|
||||
self.wait()
|
||||
|
||||
|
|
@ -163,10 +164,22 @@ class VDictTest(Scene):
|
|||
self.play(FadeOutAndShift(my_dict["r"], DOWN))
|
||||
self.wait()
|
||||
|
||||
# iterate through all submobjects currently associated with my_dict
|
||||
for submob in my_dict.get_all_submobjects():
|
||||
self.play(ShowCreation(submob))
|
||||
self.wait()
|
||||
# you can also make a VDict from an existing dict of mobjects
|
||||
plain_dict = {
|
||||
1: Integer(1).shift(DOWN),
|
||||
2: Integer(2).shift(2 * DOWN),
|
||||
3: Integer(3).shift(3 * DOWN),
|
||||
}
|
||||
|
||||
vdict_from_plain_dict = VDict(plain_dict)
|
||||
vdict_from_plain_dict.shift(1.5 * (UP + LEFT))
|
||||
self.play(ShowCreation(vdict_from_plain_dict))
|
||||
|
||||
# you can even use zip
|
||||
vdict_using_zip = VDict(zip(["s", "c", "r"], [Square(), Circle(), Rectangle()]))
|
||||
vdict_using_zip.shift(1.5 * RIGHT)
|
||||
self.play(ShowCreation(vdict_using_zip))
|
||||
self.wait()
|
||||
|
||||
|
||||
# See old_projects folder for many, many more
|
||||
|
|
|
|||
|
|
@ -877,15 +877,13 @@ class VDict(VMobject):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
pairs: Tuple[Hashable, :class:`~.VMobject`]
|
||||
Each pair is a 2-element :class:`tuple` wherein the first
|
||||
element is the key for the mobject and the second
|
||||
element is the actual mobject
|
||||
mapping_or_iterable : Union[:class:`Mapping`, Iterable[Tuple[Hashable, :class:`~.VMobject`]]], optional
|
||||
The parameter specifying the key-value mapping of keys and mobjects.
|
||||
show_keys : :class:`bool`, optional
|
||||
Whether to also display the key associated with
|
||||
the mobject. This might be useful when debugging,
|
||||
especially when there are a lot of mobjects in the
|
||||
:class:`VDict`. Defaults to False
|
||||
:class:`VDict`. Defaults to False.
|
||||
kwargs : Any
|
||||
Other arguments to be passed to `Mobject` or the CONFIG.
|
||||
|
||||
|
|
@ -897,58 +895,43 @@ class VDict(VMobject):
|
|||
especially when there are a lot of mobjects in the
|
||||
:class:`VDict`. When displayed, the key is towards
|
||||
the left of the mobject.
|
||||
Defaults to False
|
||||
Defaults to False.
|
||||
submob_dict : :class:`dict`
|
||||
Is the actual python dictionary that is used to bind
|
||||
the keys to the mobjects
|
||||
the keys to the mobjects.
|
||||
"""
|
||||
|
||||
def __init__(self, *pairs, show_keys=False, **kwargs):
|
||||
if not all(isinstance(m[1], VMobject) for m in pairs):
|
||||
raise Exception("All submobjects must be of type VMobject")
|
||||
def __init__(self, mapping_or_iterable={}, show_keys=False, **kwargs):
|
||||
VMobject.__init__(self, **kwargs)
|
||||
self.show_keys = show_keys
|
||||
self.submob_dict = {}
|
||||
self.add(*pairs)
|
||||
self.add(mapping_or_iterable)
|
||||
|
||||
def add(self, *pairs):
|
||||
def add(self, mapping_or_iterable):
|
||||
"""Adds the key-value pairs to the :class:`VDict` object.
|
||||
|
||||
Also, it internally adds the value to the `submobjects` :class:`list`
|
||||
of :class:`~.Mobject`, which is responsible for actual on-screen display
|
||||
of :class:`~.Mobject`, which is responsible for actual on-screen display.
|
||||
|
||||
Parameters
|
||||
---------
|
||||
pairs : Tuple[Hashable, :class:`~.VMobject`]
|
||||
Each pair is a :class:`tuple` wherein the first
|
||||
element is the key for the mobject and the second
|
||||
element is the actual mobject
|
||||
mapping_or_iterable : Union[:class:`Mapping`, Iterable[Tuple[Hashable, :class:`~.VMobject`]]], optional
|
||||
The parameter specifying the key-value mapping of keys and mobjects.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class:`VDict`
|
||||
Returns the :class:`VDict` object on which this method was called
|
||||
Returns the :class:`VDict` object on which this method was called.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Normal usage::
|
||||
square_obj = Square()
|
||||
my_dict.add(('s', square_obj))
|
||||
my_dict.add([('s', square_obj)])
|
||||
"""
|
||||
for pair in pairs:
|
||||
key = pair[0]
|
||||
value = pair[1]
|
||||
for key, value in dict(mapping_or_iterable).items():
|
||||
self.add_key_value_pair(key, value)
|
||||
|
||||
mob = value
|
||||
if self.show_keys:
|
||||
# This import is here and not at the top to avoid circular import
|
||||
from ...mobject.svg.tex_mobject import TextMobject
|
||||
|
||||
key_text = TextMobject(str(key)).next_to(value, LEFT)
|
||||
mob.add(key_text)
|
||||
|
||||
self.submob_dict[key] = mob
|
||||
super().add(value)
|
||||
return self
|
||||
|
||||
def remove(self, key):
|
||||
|
|
@ -960,12 +943,12 @@ class VDict(VMobject):
|
|||
Parameters
|
||||
----------
|
||||
key : Hashable
|
||||
The key of the submoject to be removed
|
||||
The key of the submoject to be removed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class:`VDict`
|
||||
Returns the :class:`VDict` object on which this method was called
|
||||
Returns the :class:`VDict` object on which this method was called.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
|
@ -973,7 +956,7 @@ class VDict(VMobject):
|
|||
my_dict.remove('square')
|
||||
"""
|
||||
if key not in self.submob_dict:
|
||||
raise Exception("The given key '%s' is not present in the VDict" % str(key))
|
||||
raise KeyError("The given key '%s' is not present in the VDict" % str(key))
|
||||
super().remove(self.submob_dict[key])
|
||||
del self.submob_dict[key]
|
||||
return self
|
||||
|
|
@ -1021,7 +1004,7 @@ class VDict(VMobject):
|
|||
"""
|
||||
if key in self.submob_dict:
|
||||
self.remove(key)
|
||||
self.add((key, value))
|
||||
self.add([(key, value)])
|
||||
|
||||
def get_all_submobjects(self):
|
||||
"""To get all the submobjects associated with a particular :class:`VDict` object
|
||||
|
|
@ -1040,6 +1023,46 @@ class VDict(VMobject):
|
|||
submobjects = self.submob_dict.values()
|
||||
return submobjects
|
||||
|
||||
def add_key_value_pair(self, key, value):
|
||||
"""A utility function used by :meth:`add` to add the key-value pair
|
||||
to :attr:`submob_dict`. Not really meant to be used externally.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
key : Hashable
|
||||
The key of the submobject to be added.
|
||||
value : :class:`~.VMobject`
|
||||
The mobject associated with the key
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
Raises
|
||||
------
|
||||
TypeError
|
||||
If the value is not an instance of VMobject
|
||||
|
||||
Examples
|
||||
--------
|
||||
Normal usage::
|
||||
square_obj = Square()
|
||||
self.add_key_value_pair('s', square_obj)
|
||||
|
||||
"""
|
||||
if not isinstance(value, VMobject):
|
||||
raise TypeError("All submobjects must be of type VMobject")
|
||||
mob = value
|
||||
if self.show_keys:
|
||||
# This import is here and not at the top to avoid circular import
|
||||
from ...mobject.svg.tex_mobject import TextMobject
|
||||
|
||||
key_text = TextMobject(str(key)).next_to(value, LEFT)
|
||||
mob.add(key_text)
|
||||
|
||||
self.submob_dict[key] = mob
|
||||
super().add(value)
|
||||
|
||||
|
||||
class VectorizedPoint(VMobject):
|
||||
CONFIG = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from manim import Mobject, VMobject, VGroup
|
||||
from manim import Mobject, VMobject, VGroup, VDict
|
||||
|
||||
|
||||
def test_vgroup_init():
|
||||
|
|
@ -29,3 +29,38 @@ def test_vgroup_add():
|
|||
with pytest.raises(Exception): # TODO change this to ValueError once #307 is merged
|
||||
# a Mobject cannot contain itself
|
||||
obj.add(obj)
|
||||
|
||||
|
||||
def test_vdict_init():
|
||||
"""Test the VDict instantiation."""
|
||||
# Test empty VDict
|
||||
VDict()
|
||||
# Test VDict made from list of pairs
|
||||
VDict([("a", VMobject()), ("b", VMobject()), ("c", VMobject())])
|
||||
# Test VDict made from a python dict
|
||||
VDict({"a": VMobject(), "b": VMobject(), "c": VMobject()})
|
||||
# Test VDict made using zip
|
||||
VDict(zip(["a", "b", "c"], [VMobject(), VMobject(), VMobject()]))
|
||||
# If the value is of type Mobject, must raise a TypeError
|
||||
with pytest.raises(TypeError):
|
||||
VDict({"a": Mobject()})
|
||||
|
||||
|
||||
def test_vdict_add():
|
||||
"""Test the VDict add method."""
|
||||
obj = VDict()
|
||||
assert len(obj.submob_dict) == 0
|
||||
obj.add([("a", VMobject())])
|
||||
assert len(obj.submob_dict) == 1
|
||||
with pytest.raises(TypeError):
|
||||
obj.add([("b", Mobject())])
|
||||
|
||||
|
||||
def test_vdict_remove():
|
||||
"""Test the VDict remove method."""
|
||||
obj = VDict([("a", VMobject())])
|
||||
assert len(obj.submob_dict) == 1
|
||||
obj.remove("a")
|
||||
assert len(obj.submob_dict) == 0
|
||||
with pytest.raises(KeyError):
|
||||
obj.remove("a")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<path style="stroke:none;" d="M 1.25 0 L 1.25 -6.25 L 6.25 -6.25 L 6.25 0 Z M 1.40625 -0.15625 L 6.09375 -0.15625 L 6.09375 -6.09375 L 1.40625 -6.09375 Z M 1.40625 -0.15625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M -0.152344 1.988281 L -0.152344 1.351562 L 5.671875 1.351562 L 5.671875 1.988281 Z M -0.152344 1.988281 "/>
|
||||
<path style="stroke:none;" d="M -0.152344 1.988281 L -0.152344 1.351563 L 5.671875 1.351563 L 5.671875 1.988281 Z M -0.152344 1.988281 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 761 B |
Loading…
Add table
Add a link
Reference in a new issue