:class:~.MathTex, :class:~.Tex, :class:~.Text and :class:~.MarkupText inherit color from their parent mobjects. (#2467)

* comment out color-related things from tex_mob

* add change to svg_mobject

* MarkupText handles colour internally

* MarkupText handles colour internally

* make coordinate_system.py colour agnostic

* get_line_from_axis_to_point

* add typings for SingleStringMathTex

* add typings for MathTex

* make internal methods internal

* black + isort

* fix typo

* black + isort

* fix typo

* revert internalizing change

* Revert "Merge branch 'mathtexx' of https://github.com/hydrobeam/manim into mathtexx"

This reverts commit 6be3c39814, reversing
changes made to 2b30b446ae.

* remove accidental import

* do it in a less bad way

* WIP: Text2setting causing problems

* allow tex_mobject.py to inherit colour

* allow tex_mobject.py to inherit colour

* add tests

* remove undeedde imports + formatting

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix warnings from pre-commit hooks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix some tests

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* remove other color_inheritance test

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix typo

* accomodate the color->attribute PR

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix tests and doc build

add a check for None when inheriting colour in
`coordinate_systems.py`, and turn written tests
into graphical tests

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Comment out `Text` color inheritance test.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Set font for text_color_inheritance test

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Small change to retrigger docs build

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Laith Bahodi 2022-02-19 13:57:19 -05:00 committed by GitHub
commit 2275ec5916
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 110 additions and 44 deletions

View file

@ -49,7 +49,6 @@ from ..utils.color import (
BLUE,
BLUE_D,
GREEN,
LIGHT_GREY,
WHITE,
YELLOW,
color_gradient,
@ -487,7 +486,7 @@ class CoordinateSystem:
point: Sequence[float],
line_func: Line = DashedLine,
line_config: dict | None = None,
color: Color = LIGHT_GREY,
color: Color | None = None,
stroke_width: float = 2,
) -> Line:
"""Returns a straight line from a given axis to a point in the scene.
@ -517,9 +516,15 @@ class CoordinateSystem:
:meth:`~.CoordinateSystem.get_vertical_line`
:meth:`~.CoordinateSystem.get_horizontal_line`
"""
line_config = line_config if line_config is not None else {}
if color is None:
color = VMobject().color
line_config["color"] = color
line_config["stroke_width"] = stroke_width
axis = self.get_axis(index)
line = line_func(axis.get_projection(point), point, **line_config)
return line
@ -977,9 +982,8 @@ class CoordinateSystem:
if dot_config is None:
dot_config = {}
label = self.x_axis._create_label_tex(label)
color = color or graph.get_color()
label.set_color(color)
label = self.x_axis._create_label_tex(label).set_color(color)
if x_val is None:
# Search from right to left
@ -1630,9 +1634,9 @@ class CoordinateSystem:
x_val: float,
graph: ParametricFunction,
label: float | str | Mobject | None = None,
label_color: Color = WHITE,
label_color: Color | None = None,
triangle_size: float = MED_SMALL_BUFF,
triangle_color: Color = WHITE,
triangle_color: Color | None = WHITE,
line_func: Line = Line,
line_color: Color = YELLOW,
) -> VGroup:
@ -1688,7 +1692,7 @@ class CoordinateSystem:
triangle.height = triangle_size
triangle.move_to(self.coords_to_point(x_val, 0), UP)
if label is not None:
t_label = self.x_axis._create_label_tex(label).set_color(label_color)
t_label = self.x_axis._create_label_tex(label, color=label_color)
t_label.next_to(triangle, DOWN)
T_label_group.add(t_label)
@ -2338,7 +2342,6 @@ class NumberPlane(Axes):
# configs
self.axis_config = {
"stroke_color": WHITE,
"stroke_width": 2,
"include_ticks": False,
"include_tip": False,
@ -2626,7 +2629,6 @@ class PolarPlane(Axes):
# configs
self.radius_config = {
"stroke_color": WHITE,
"stroke_width": 2,
"include_ticks": False,
"include_tip": False,
@ -3012,7 +3014,7 @@ class ComplexPlane(NumberPlane):
Returns
-------
List[Union[float, complex]]
List[float | complex]
A list of floats representing the x-axis and complex numbers representing the y-axis.
"""
x_numbers = self.get_x_axis().get_tick_range()

View file

@ -27,7 +27,7 @@ class NumberLine(Line):
Parameters
----------
x_range
The :code:`[x_min, x_max, x_step]` values to create the line.
The ``[x_min, x_max, x_step]`` values to create the line.
length
The length of the number line.
unit_size
@ -559,7 +559,9 @@ class NumberLine(Line):
self.add(labels)
return self
def _create_label_tex(self, label_tex: str | float | VMobject) -> VMobject:
def _create_label_tex(
self, label_tex: str | float | VMobject, **kwargs
) -> VMobject:
"""Checks if the label is a :class:`~.VMobject`, otherwise, creates a
label according to the ``label_constructor``.
@ -579,7 +581,7 @@ class NumberLine(Line):
if isinstance(label_tex, VMobject):
return label_tex
else:
return self.label_constructor(label_tex)
return self.label_constructor(label_tex, **kwargs)
@staticmethod
def _decimal_places_from_step(step) -> int:

View file

@ -82,6 +82,7 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
stroke_opacity=1.0,
**kwargs,
):
self.def_map = {}
self.file_name = file_name or self.file_name
self._ensure_valid_file()

View file

@ -27,16 +27,18 @@ import operator as op
import re
from functools import reduce
from textwrap import dedent
from typing import Dict, Iterable, Optional
from colour import Color
from manim.utils.tex import TexTemplate
from ... import config, logger
from ...constants import *
from ...mobject.geometry import Line
from ...mobject.svg.svg_mobject import SVGMobject
from ...mobject.svg.svg_path import SVGPathMobject
from ...mobject.types.vectorized_mobject import VectorizedPoint, VGroup
from ...utils.color import BLACK, WHITE
from ...mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject
from ...utils.tex_file_writing import tex_to_svg_file
from .style_utils import parse_style
@ -64,21 +66,22 @@ class SingleStringMathTex(SVGMobject):
def __init__(
self,
tex_string,
stroke_width=0,
fill_opacity=1.0,
background_stroke_width=0,
background_stroke_color=BLACK,
should_center=True,
height=None,
organize_left_to_right=False,
tex_environment="align*",
tex_template=None,
font_size=DEFAULT_FONT_SIZE,
color=Color(WHITE),
tex_string: str,
stroke_width: float = 0,
should_center: bool = True,
height: float | None = None,
organize_left_to_right: bool = False,
tex_environment: str = "align*",
tex_template: TexTemplate | None = None,
font_size: float = DEFAULT_FONT_SIZE,
**kwargs,
):
if kwargs.get("color") is None:
# makes it so that color isn't explicitly passed for these mobs,
# and can instead inherit from the parent
kwargs["color"] = VMobject().color
self._font_size = font_size
self.organize_left_to_right = organize_left_to_right
self.tex_environment = tex_environment
@ -98,12 +101,8 @@ class SingleStringMathTex(SVGMobject):
should_center=should_center,
stroke_width=stroke_width,
height=height,
fill_opacity=fill_opacity,
background_stroke_width=background_stroke_width,
background_stroke_color=background_stroke_color,
should_subdivide_sharp_curves=True,
should_remove_null_curves=True,
color=color,
**kwargs,
)
# used for scaling via font_size.setter
@ -263,10 +262,10 @@ class MathTex(SingleStringMathTex):
def __init__(
self,
*tex_strings,
arg_separator=" ",
substrings_to_isolate=None,
tex_to_color_map=None,
tex_environment="align*",
arg_separator: str = " ",
substrings_to_isolate: Iterable[str] | None = None,
tex_to_color_map: dict[str, Color] = None,
tex_environment: str = "align*",
**kwargs,
):
self.tex_template = kwargs.pop("tex_template", config["tex_template"])

View file

@ -70,8 +70,8 @@ from ... import config, logger
from ...constants import *
from ...mobject.geometry import Dot
from ...mobject.svg.svg_mobject import SVGMobject
from ...mobject.types.vectorized_mobject import VGroup
from ...utils.color import WHITE, Colors, color_gradient
from ...mobject.types.vectorized_mobject import VGroup, VMobject
from ...utils.color import Colors, color_gradient
from ...utils.deprecation import deprecated
TEXT_MOB_SCALE_FACTOR = 0.05
@ -406,7 +406,7 @@ class Text(SVGMobject):
text: str,
fill_opacity: float = 1.0,
stroke_width: float = 0,
color: Color = WHITE,
color: Color | None = None,
font_size: float = DEFAULT_FONT_SIZE,
line_spacing: float = -1,
font: str = "",
@ -427,6 +427,7 @@ class Text(SVGMobject):
disable_ligatures: bool = False,
**kwargs,
):
self.line_spacing = line_spacing
self.font = font
self._font_size = float(font_size)
@ -470,6 +471,8 @@ class Text(SVGMobject):
)
else:
self.line_spacing = self._font_size + self._font_size * self.line_spacing
color = Color(color) if color else VMobject().color
file_name = self._text2svg(color)
PangoUtils.remove_last_M(file_name)
super().__init__(
@ -596,7 +599,7 @@ class Text(SVGMobject):
def _text2hash(self, color: Color):
"""Generates ``sha256`` hash for file name."""
settings = (
"PANGO" + self.font + self.slant + self.weight + color
"PANGO" + self.font + self.slant + self.weight + color.hex_l
) # to differentiate Text and CairoText
settings += str(self.t2f) + str(self.t2s) + str(self.t2w) + str(self.t2c)
settings += str(self.line_spacing) + str(self._font_size)
@ -683,8 +686,9 @@ class Text(SVGMobject):
(self.t2w, "weight"),
(self.t2c, "color"),
]
# setting_args requires values to be strings
default_args = {
arg: getattr(self, arg) if arg != "color" else color for _, arg in t2xs
arg: getattr(self, arg) if arg != "color" else str(color) for _, arg in t2xs
}
settings = self._get_settings_from_t2xs(t2xs, default_args)
@ -737,6 +741,7 @@ class Text(SVGMobject):
for setting in settings:
if setting.line_num == -1:
setting.line_num = line_num
return settings
def _text2svg(self, color: Color):
@ -896,8 +901,6 @@ class MarkupText(SVGMobject):
The fill opacity with 1 meaning opaque and 0 meaning transparent.
stroke_width : :class:`int`
Stroke width.
color : :class:`str`
Global color setting for the entire text. Local overrides are possible.
font_size : :class:`float`
Font size.
line_spacing : :class:`int`
@ -1089,7 +1092,7 @@ class MarkupText(SVGMobject):
text: str,
fill_opacity: float = 1,
stroke_width: float = 0,
color: Color = WHITE,
color: Color | None = None,
font_size: float = DEFAULT_FONT_SIZE,
line_spacing: int = -1,
font: str = "",
@ -1105,6 +1108,7 @@ class MarkupText(SVGMobject):
disable_ligatures: bool = False,
**kwargs,
):
self.text = text
self.line_spacing = line_spacing
self.font = font
@ -1138,7 +1142,9 @@ class MarkupText(SVGMobject):
else:
self.line_spacing = self._font_size + self._font_size * self.line_spacing
file_name = self._text2svg(Color(color) if color else None)
color = Color(color) if color else VMobject().color
file_name = self._text2svg(color)
PangoUtils.remove_last_M(file_name)
super().__init__(
file_name,
@ -1150,6 +1156,7 @@ class MarkupText(SVGMobject):
unpack_groups=unpack_groups,
**kwargs,
)
self.chars = self.get_group_class()(*self.submobjects)
self.text = text_without_tabs.replace(" ", "").replace("\n", "")

View file

@ -0,0 +1,20 @@
import pytest
from manim import *
from manim.utils.testing.frames_comparison import frames_comparison
__module_test__ = "tex_mobject"
@frames_comparison
def test_color_inheritance(scene):
"""Test that Text and MarkupText correctly inherit colour from
their parent class."""
VMobject.set_default(color=RED)
tex = Tex("test color inheritance")
mathtex = MathTex("test color inheritance")
vgr = VGroup(tex, mathtex).arrange()
VMobject.set_default()
scene.add(vgr)

View file

@ -13,3 +13,23 @@ __module_test__ = "text"
@frames_comparison
def test_Text2Color(scene):
scene.add(Text("this is a text with spaces!", t2c={"spaces": RED}))
@pytest.mark.skipif(
not sys.platform.startswith("linux"),
reason="MacOS and Windows render fonts differently, so they need separate comparison data.",
)
@frames_comparison
def test_text_color_inheritance(scene):
"""Test that Text and MarkupText correctly inherit colour from
their parent class."""
VMobject.set_default(color=RED)
# set both to a singular font so that the tests agree.
text = Text("test_color_inheritance", font="Dejavu Sans")
markup_text = MarkupText("test_color_inheritance", font="Dejavu Sans")
vgr = VGroup(text, markup_text).arrange()
# reset the default color so that future tests aren't affected by this change.
VMobject.set_default()
scene.add(vgr)

View file

@ -5,6 +5,8 @@ from pathlib import Path
import pytest
from manim import MathTex, SingleStringMathTex, Tex, TexTemplate, config
from manim.mobject.types.vectorized_mobject import VMobject
from manim.utils.color import RED
def test_MathTex():

View file

@ -1,6 +1,11 @@
from __future__ import annotations
import pytest
from colour import Color
from manim.mobject.svg.text_mobject import MarkupText, Text
from manim.mobject.types.vectorized_mobject import VMobject
from manim.utils.color import RED
def test_font_size():
@ -11,3 +16,11 @@ def test_font_size():
assert round(text_string.font_size, 5) == 14.4
assert round(markuptext_string.font_size, 5) == 14.4
def test_non_str_color():
"""Test that the Text and MarkupText can accept non_str color values
i.e. colour.Color(red)."""
text = Text("test_color_inheritance", color=Color("blue"))
markup_text = MarkupText("test_color_inheritance", color=Color("blue"))