3b1b / manim

Animation engine for explanatory math videos
MIT License
68.01k stars 6.07k forks source link

Unable to add SVGMobject to Scene #720

Closed manul-goyal closed 4 years ago

manul-goyal commented 5 years ago

I am trying to add a SVG image to a Scene in manim. It is named "AND_DIN". It gives the following error:

Traceback (most recent call last): File "/home/manul/animations/manim/manimlib/extract_scene.py", line 155, in main scene = SceneClass(**scene_kwargs) File "/home/manul/animations/manim/manimlib/scene/scene.py", line 53, in __init__ self.construct() File "./mytry/gates.py", line 13, in construct gate = AndGate() File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 46, in __init__ VMobject.__init__(self, **kwargs) File "/home/manul/animations/manim/manimlib/mobject/mobject.py", line 48, in __init__ self.generate_points() File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 69, in generate_points mobjects = self.get_mobjects_from(svg) File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 87, in get_mobjects_from for child in element.childNodes File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 87, in <listcomp> for child in element.childNodes File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 81, in get_mobjects_from self.update_ref_to_element(element) File "/home/manul/animations/manim/manimlib/mobject/svg/svg_mobject.py", line 307, in update_ref_to_element new_refs = dict([(e.getAttribute('id'), e) for e in self.get_all_childNodes_have_id(defs)]) TypeError: 'Element' object is not iterable

Link to the SVG File: https://upload.wikimedia.org/wikipedia/commons/b/b4/AND_DIN.svg

The scene file is given below:

`from manimlib.imports import *

class AndGate(SVGMobject): CONFIG = { "file_name" : "AND_DIN", "stroke_width" : 2, "fill_opacity" : 0, "height" : 0.5, }

class Shapes(Scene): def construct(self): gate = AndGate() self.add(gate)`

yoshiask commented 5 years ago

For the record, even just opening that SVG in a browser throws what appears to be a similar error. The SVG still gets drawn, but the console reveals that there are a couple of errors involving child nodes.

Note that manim fails at self.get_all_childNodes_have_id(defs)]), and Chromium reports Cannot read property 'childNodes' of null and Cannot read property 'querySelectorAll' of null

image

DzyubSpirit commented 5 years ago

@yoshiask, I'm not sure but I think these errors are caused by your browser extensions. I don't get them

DzyubSpirit commented 5 years ago

I think that the problem is that the function returns element instead of the [element] here: https://github.com/3b1b/manim/blob/master/manimlib/mobject/svg/svg_mobject.py#L301).

DzyubSpirit commented 5 years ago

I also manually changed an SVG a bit. It was not showing pins of the logical gate using manim. This shows an issue with SVG visualization in manim but this is another problem, I will do a separate issue for that.

New SVG

sterlingbates commented 5 years ago

@DzyubSpirit Unfortunately that fix doesn't appear to correct the problem. In an SVG with a defs element, but no references to it, get_all_childNodes_have_id will still return the one defs element, throwing the Element-not-iterable error.

The reason is that these lines are still getting hit, and they return the singleton Element instance:

        if element.hasAttribute('id'):
            return element

If that's the correct behavior for that function then I'd recommend modifying update_ref_to_element to the following, which works for me.

    def update_ref_to_element(self, defs):
        childNodesWithId = self.get_all_childNodes_have_id(defs)
        if not isinstance(childNodesWithId, minidom.Element):
            new_refs = dict([(e.getAttribute('id'), e) for e in childNodesWithId])
            self.ref_to_element.update(new_refs)
DzyubSpirit commented 5 years ago

@sterlingbates, a new SVG doesn't fix the problem, but my PR #746 fixes it. It is similar to your solution but instead always returns the list of elements which, in my opinion, is better than checking the type of the result.

A new SVG fixes the problem that comes after the fix which is that the default line width is 0. Fixing that here #748 .