Manim: CairoText not working with strings that are longer than 30 lines

Created on 20 Nov 2020  路  5Comments  路  Source: ManimCommunity/manim

Description of bug / unexpected behavior

When I read a file of any text that is longer than 30 lines and use the resulting string to create a CairoText object, the creation crashes with the exception shown below. Standard setup as described in the documentation (Windows 10). But I think it has nothing to do with the setup.

How to reproduce the issue

from manim import *

class Test(Scene):
    def construct(self):
        with open("<path to file that has more than 30 lines>") as f:
            code_raw = f.read()

        code = CairoText(code_raw)

Logs

Traceback (most recent call last):
  File "C:\Users\Chris\Documents\repos\manim\manim\__main__.py", line 75, in main
    scene.render()
  File "C:\Users\Chris\Documents\repos\manim\manim\scene\scene.py", line 88, in render
    self.construct()
  File "test.py", line 10, in construct
    code = CairoText(code_raw)
  File "C:\Users\Chris\Documents\repos\manim\manim\mobject\svg\text_mobject.py", line 136, in __init__
    self.submobjects = [*self.gen_chars()]
  File "C:\Users\Chris\Documents\repos\manim\manim\mobject\svg\text_mobject.py", line 187, in gen_chars
    chars.add(self.submobjects[submobjects_char_index])
IndexError: list index out of range

Process finished with exit code 0
bug

Most helpful comment

There appears to be a limit on the actual width of the string that shows up on screen.

| Character | Max Number in string | Max Width| Single Char Width |
| ----------- | ----------- | -----------|------------------|
| A | 101 | 33.66953125| 0.31992185
| B | 101 |33.6261719| 0.2765625|
|a| 121 | 33.6166015| 0.2474609|
|莿| 55| 33.9277344| 0.5732422|

Any string lengthier than about 34 MUnits (without any scaling) seems to cause the IndexError.

If the string does turn out to be lengthier than 34 MUnits, CairoText.submobjects will be locked down to the number of characters whose length is lesser than 34 MUnits.

For example, if I try CairoText(101*"A"), everything works fine. CairoText.submobjects has exactly 101 elements.

BUT, if I try CairoText(102*"A"), CairoText.submobjects still only has 101 elements, and that causes the list index out of range error when CairoText.gen_chars tries to generate the 102nd "A", with the nonexistent 102nd element of CairoText.submobjects.

The same goes for 103*"A", 231*"A" and so on. In all cases with the letter "A" alone repeating more than 101 times, CairoText.submobjects has only 101 elements.

So I kept checking when the submobjects were actually created and in what order and traced it back to SVGMobject.generate_points.

And that is where I stopped investigating, because this _looks_ like a bug in SVGMobject's generate_points method, and SVGMobject is scary.

All 5 comments

Thanks for reporting @ChristianCoenen. I can confirm this bug on latest master (even with a hard-coded very long string, no file involved).

There appears to be a limit on the actual width of the string that shows up on screen.

| Character | Max Number in string | Max Width| Single Char Width |
| ----------- | ----------- | -----------|------------------|
| A | 101 | 33.66953125| 0.31992185
| B | 101 |33.6261719| 0.2765625|
|a| 121 | 33.6166015| 0.2474609|
|莿| 55| 33.9277344| 0.5732422|

Any string lengthier than about 34 MUnits (without any scaling) seems to cause the IndexError.

If the string does turn out to be lengthier than 34 MUnits, CairoText.submobjects will be locked down to the number of characters whose length is lesser than 34 MUnits.

For example, if I try CairoText(101*"A"), everything works fine. CairoText.submobjects has exactly 101 elements.

BUT, if I try CairoText(102*"A"), CairoText.submobjects still only has 101 elements, and that causes the list index out of range error when CairoText.gen_chars tries to generate the 102nd "A", with the nonexistent 102nd element of CairoText.submobjects.

The same goes for 103*"A", 231*"A" and so on. In all cases with the letter "A" alone repeating more than 101 times, CairoText.submobjects has only 101 elements.

So I kept checking when the submobjects were actually created and in what order and traced it back to SVGMobject.generate_points.

And that is where I stopped investigating, because this _looks_ like a bug in SVGMobject's generate_points method, and SVGMobject is scary.

Great work. Yes, unfortunately, SVGMobject is not in good shape.

This is basically what I tried to fix with #476. For CairoText, we still might be able to fix it -- and Pango needs a bit more work anyways.

There appears to be a limit on the actual width of the string that shows up on screen.

Character Max Number in string Max Width Single Char Width
A 101 33.66953125 0.31992185
B 101 33.6261719 0.2765625
a 121 33.6166015 0.2474609
莿 55 33.9277344 0.5732422
Any string lengthier than about 34 MUnits (without any scaling) seems to cause the IndexError.

If the string does turn out to be lengthier than 34 MUnits, CairoText.submobjects will be locked down to the number of characters whose length is lesser than 34 MUnits.

For example, if I try CairoText(101*"A"), everything works fine. CairoText.submobjects has exactly 101 elements.

BUT, if I try CairoText(102*"A"), CairoText.submobjects still only has 101 elements, and that causes the list index out of range error when CairoText.gen_chars tries to generate the 102nd "A", with the nonexistent 102nd element of CairoText.submobjects.

The same goes for 103*"A", 231*"A" and so on. In all cases with the letter "A" alone repeating more than 101 times, CairoText.submobjects has only 101 elements.

So I kept checking when the submobjects were actually created and in what order and traced it back to SVGMobject.generate_points.

And that is where I stopped investigating, because this _looks_ like a bug in SVGMobject's generate_points method, and SVGMobject is scary.

Does this also explain why the following string fails? Because i wouldn't assume that the whitespace is so 'wide' and its just 30 occurances. It also doesn't result in a horizontally wide text but vertically one. I'd definetely double check the '\n' string below when trying to fix it. Might be an edge case.

# This string fails. If you remove one \n it is working.
s = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\na"
t = CairoText(s)
Was this page helpful?
0 / 5 - 0 ratings