Repository: ManimCommunity/manim

Issue:
`Transform` two plots into one causes color error
## Description of bug / unexpected behavior
<!-- Add a clear and concise description of the problem you encountered. -->
This bug is being experienced when using the most recent `main` branch retrieved on February 25, 2022.  The most recent release, v0.14.0,  does not have this bug.

When transforming two plots into one, Manim outputs the error shown in the "Logs" section below.  Code which causes the issue is below in the "How to reproduce the issue" section.

## Expected behavior
<!-- Add a clear and concise description of what you expected to happen. -->
The animation should run and not throw an error.

## How to reproduce the issue
<!-- Provide a piece of code illustrating the undesired behavior. -->

<details><summary>Code for reproducing the problem</summary>

```py
from manim import *
import numpy as np


class Test(Scene):
    def construct(self):
        axes1 = Axes(
                x_range = [0, 10],
                y_range = [0, 5],
                )
        curve1 = axes1.plot(
                lambda x: np.sin(x) + 2.0,
                color = PURE_RED,
                )

        axes2 = Axes(
                x_range = [0, 10],
                y_range = [0, 5],
                )
        curve2 = axes2.plot(
                lambda x: np.cos(x) + 2,
                color = ORANGE,
                )

        axes3 = Axes(
                x_range = [0, 10],
                y_range = [0, 5],
                )
        curve3 = axes3.plot(
                lambda x: np.cos(x) + 2.0,
                color = BLUE,
                )

        VGroup(axes1, curve1).scale(0.5).to_edge(LEFT)
        VGroup(axes2, curve2).scale(0.5).to_edge(RIGHT)

        self.add(axes1, axes2, curve1, curve2)

        self.play(ReplacementTransform(
            VGroup(axes1, curve1, axes2, curve2),
            VGroup(axes3, curve3)
            ))

        self.wait(2)
```

</details>


## Logs
<details><summary>Terminal output</summary>
<!-- Add "-v DEBUG" when calling manim to generate more detailed logs -->

```
$ manim double_plot.py Test -ql -p
Manim Community v0.14.0

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/cli/render/commands.py:141 in render  │
│                                                                                                  │
│   138 │   │   for SceneClass in scene_classes_from_file(file):                                   │
│   139 │   │   │   try:                                                                           │
│   140 │   │   │   │   scene = SceneClass()                                                       │
│ ❱ 141 │   │   │   │   scene.render()                                                             │
│   142 │   │   │   except Exception:                                                              │
│   143 │   │   │   │   error_console.print_exception()                                            │
│   144 │   │   │   │   sys.exit(1)                                                                │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/scene/scene.py:221 in render          │
│                                                                                                  │
│    218 │   │   """                                                                               │
│    219 │   │   self.setup()                                                                      │
│    220 │   │   try:                                                                              │
│ ❱  221 │   │   │   self.construct()                                                              │
│    222 │   │   except EndSceneEarlyException:                                                    │
│    223 │   │   │   pass                                                                          │
│    224 │   │   except RerunSceneException as e:                                                  │
│                                                                                                  │
│ /home/alexlembcke/ManimDev/double_plot.py:39 in construct                                        │
│                                                                                                  │
│   36 │   │                                                                                       │
│   37 │   │   self.add(axes1, axes2, curve1, curve2)                                              │
│   38 │   │                                                                                       │
│ ❱ 39 │   │   self.play(Transform(                                                                │
│   40 │   │   │   VGroup(axes1, curve1, axes2, curve2),                                           │
│   41 │   │   │   VGroup(axes3, curve3)                                                           │
│   42 │   │   │   ))                                                                              │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/scene/scene.py:956 in play            │
│                                                                                                  │
│    953 │   │                                                                                     │
│    954 │   │   """                                                                               │
│    955 │   │   start_time = self.renderer.time                                                   │
│ ❱  956 │   │   self.renderer.play(self, *args, **kwargs)                                         │
│    957 │   │   run_time = self.renderer.time - start_time                                        │
│    958 │   │   if subcaption:                                                                    │
│    959 │   │   │   if subcaption_duration is None:                                               │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/renderer/cairo_renderer.py:93 in play │
│                                                                                                  │
│    90 │   │   self.static_image = self.save_static_frame_data(scene, scene.static_mobjects)      │
│    91 │   │                                                                                      │
│    92 │   │   self.file_writer.begin_animation(not self.skip_animations)                         │
│ ❱  93 │   │   scene.begin_animations()                                                           │
│    94 │   │   if scene.is_current_animation_frozen_frame():                                      │
│    95 │   │   │   self.update_frame(scene)                                                       │
│    96 │   │   │   # self.duration stands for the total run time of all the animations.           │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/scene/scene.py:1090 in                │
│ begin_animations                                                                                 │
│                                                                                                  │
│   1087 │   │   """Start the animations of the scene."""                                          │
│   1088 │   │   for animation in self.animations:                                                 │
│   1089 │   │   │   animation._setup_scene(self)                                                  │
│ ❱ 1090 │   │   │   animation.begin()                                                             │
│   1091 │                                                                                         │
│   1092 │   def is_current_animation_frozen_frame(self) -> bool:                                  │
│   1093 │   │   """Returns whether the current animation produces a static frame (generally a Wa  │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/animation/transform.py:122 in begin   │
│                                                                                                  │
│   119 │   │   if config["renderer"] == "opengl":                                                 │
│   120 │   │   │   self.mobject.align_data_and_family(self.target_copy)                           │
│   121 │   │   else:                                                                              │
│ ❱ 122 │   │   │   self.mobject.align_data(self.target_copy)                                      │
│   123 │   │   super().begin()                                                                    │
│   124 │                                                                                          │
│   125 │   def create_target(self) -> Mobject:                                                    │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2493 in align_data │
│                                                                                                  │
│   2490 │   │   │   self.align_points(mobject)                                                    │
│   2491 │   │   # Recurse                                                                         │
│   2492 │   │   for m1, m2 in zip(self.submobjects, mobject.submobjects):                         │
│ ❱ 2493 │   │   │   m1.align_data(m2)                                                             │
│   2494 │                                                                                         │
│   2495 │   def get_point_mobject(self, center=None):                                             │
│   2496 │   │   """The simplest :class:`~.Mobject` to be transformed to or from self.             │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2493 in align_data │
│                                                                                                  │
│   2490 │   │   │   self.align_points(mobject)                                                    │
│   2491 │   │   # Recurse                                                                         │
│   2492 │   │   for m1, m2 in zip(self.submobjects, mobject.submobjects):                         │
│ ❱ 2493 │   │   │   m1.align_data(m2)                                                             │
│   2494 │                                                                                         │
│   2495 │   def get_point_mobject(self, center=None):                                             │
│   2496 │   │   """The simplest :class:`~.Mobject` to be transformed to or from self.             │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2488 in align_data │
│                                                                                                  │
│   2485 │   │   │   point alignment is skipped (default: False).                                  │
│   2486 │   │   """                                                                               │
│   2487 │   │   self.null_point_align(mobject)                                                    │
│ ❱ 2488 │   │   self.align_submobjects(mobject)                                                   │
│   2489 │   │   if not skip_point_alignment:                                                      │
│   2490 │   │   │   self.align_points(mobject)                                                    │
│   2491 │   │   # Recurse                                                                         │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2519 in            │
│ align_submobjects                                                                                │
│                                                                                                  │
│   2516 │   │   mob2 = mobject                                                                    │
│   2517 │   │   n1 = len(mob1.submobjects)                                                        │
│   2518 │   │   n2 = len(mob2.submobjects)                                                        │
│ ❱ 2519 │   │   mob1.add_n_more_submobjects(max(0, n2 - n1))                                      │
│   2520 │   │   mob2.add_n_more_submobjects(max(0, n1 - n2))                                      │
│   2521 │   │   return self                                                                       │
│   2522                                                                                           │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2553 in            │
│ add_n_more_submobjects                                                                           │
│                                                                                                  │
│   2550 │   │   curr = len(self.submobjects)                                                      │
│   2551 │   │   if curr == 0:                                                                     │
│   2552 │   │   │   # If empty, simply add n point mobjects                                       │
│ ❱ 2553 │   │   │   self.submobjects = [self.get_point_mobject() for k in range(n)]               │
│   2554 │   │   │   return                                                                        │
│   2555 │   │                                                                                     │
│   2556 │   │   target = curr + n                                                                 │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/mobject.py:2553 in <listcomp> │
│                                                                                                  │
│   2550 │   │   curr = len(self.submobjects)                                                      │
│   2551 │   │   if curr == 0:                                                                     │
│   2552 │   │   │   # If empty, simply add n point mobjects                                       │
│ ❱ 2553 │   │   │   self.submobjects = [self.get_point_mobject() for k in range(n)]               │
│   2554 │   │   │   return                                                                        │
│   2555 │   │                                                                                     │
│   2556 │   │   target = curr + n                                                                 │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:1 │
│ 554 in get_point_mobject                                                                         │
│                                                                                                  │
│   1551 │   │   if center is None:                                                                │
│   1552 │   │   │   center = self.get_center()                                                    │
│   1553 │   │   point = VectorizedPoint(center)                                                   │
│ ❱ 1554 │   │   point.match_style(self)                                                           │
│   1555 │   │   return point                                                                      │
│   1556 │                                                                                         │
│   1557 │   def interpolate_color(self, mobject1, mobject2, alpha):                               │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:3 │
│ 43 in match_style                                                                                │
│                                                                                                  │
│    340 │   │   return ret                                                                        │
│    341 │                                                                                         │
│    342 │   def match_style(self, vmobject, family=True):                                         │
│ ❱  343 │   │   self.set_style(**vmobject.get_style(), family=False)                              │
│    344 │   │                                                                                     │
│    345 │   │   if family:                                                                        │
│    346 │   │   │   # Does its best to match up submobject lists, and                             │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:3 │
│ 03 in set_style                                                                                  │
│                                                                                                  │
│    300 │   │   │   opacity=stroke_opacity,                                                       │
│    301 │   │   │   family=family,                                                                │
│    302 │   │   )                                                                                 │
│ ❱  303 │   │   self.set_background_stroke(                                                       │
│    304 │   │   │   color=background_stroke_color,                                                │
│    305 │   │   │   width=background_stroke_width,                                                │
│    306 │   │   │   opacity=background_stroke_opacity,                                            │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:2 │
│ 78 in set_background_stroke                                                                      │
│                                                                                                  │
│    275 │                                                                                         │
│    276 │   def set_background_stroke(self, **kwargs):                                            │
│    277 │   │   kwargs["background"] = True                                                       │
│ ❱  278 │   │   self.set_stroke(**kwargs)                                                         │
│    279 │   │   return self                                                                       │
│    280 │                                                                                         │
│    281 │   def set_style(                                                                        │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:2 │
│ 67 in set_stroke                                                                                 │
│                                                                                                  │
│    264 │   │   │   array_name = "stroke_rgbas"                                                   │
│    265 │   │   │   width_name = "stroke_width"                                                   │
│    266 │   │   │   opacity_name = "stroke_opacity"                                               │
│ ❱  267 │   │   self.update_rgbas_array(array_name, color, opacity)                               │
│    268 │   │   if width is not None:                                                             │
│    269 │   │   │   setattr(self, width_name, width)                                              │
│    270 │   │   if opacity is not None:                                                           │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:1 │
│ 79 in update_rgbas_array                                                                         │
│                                                                                                  │
│    176 │   def update_rgbas_array(self, array_name, color=None, opacity=None):                   │
│    177 │   │   passed_color = color if (color is not None) else BLACK                            │
│    178 │   │   passed_opacity = opacity if (opacity is not None) else 0                          │
│ ❱  179 │   │   rgbas = self.generate_rgbas_array(passed_color, passed_opacity)                   │
│    180 │   │   if not hasattr(self, array_name):                                                 │
│    181 │   │   │   setattr(self, array_name, rgbas)                                              │
│    182 │   │   │   return self                                                                   │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:1 │
│ 65 in generate_rgbas_array                                                                       │
│                                                                                                  │
│    162 │   │   colors = list(tuplify(color))                                                     │
│    163 │   │   opacities = list(tuplify(opacity))                                                │
│    164 │   │   rgbas = np.array(                                                                 │
│ ❱  165 │   │   │   [color_to_rgba(c, o) for c, o in zip(*make_even(colors, opacities))],         │
│    166 │   │   )                                                                                 │
│    167 │   │                                                                                     │
│    168 │   │   sheen_factor = self.get_sheen_factor()                                            │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/mobject/types/vectorized_mobject.py:1 │
│ 65 in <listcomp>                                                                                 │
│                                                                                                  │
│    162 │   │   colors = list(tuplify(color))                                                     │
│    163 │   │   opacities = list(tuplify(opacity))                                                │
│    164 │   │   rgbas = np.array(                                                                 │
│ ❱  165 │   │   │   [color_to_rgba(c, o) for c, o in zip(*make_even(colors, opacities))],         │
│    166 │   │   )                                                                                 │
│    167 │   │                                                                                     │
│    168 │   │   sheen_factor = self.get_sheen_factor()                                            │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/utils/color.py:464 in color_to_rgba   │
│                                                                                                  │
│   461                                                                                            │
│   462                                                                                            │
│   463 def color_to_rgba(color: Color | str, alpha: float = 1) -> np.ndarray:                     │
│ ❱ 464 │   return np.array([*color_to_rgb(color), alpha])                                         │
│   465                                                                                            │
│   466                                                                                            │
│   467 def rgb_to_color(rgb: Iterable[float]) -> Color:                                           │
│                                                                                                  │
│ /home/alexlembcke/.local/lib/python3.9/site-packages/manim/utils/color.py:460 in color_to_rgb    │
│                                                                                                  │
│   457 │   elif isinstance(color, Color):                                                         │
│   458 │   │   return np.array(color.get_rgb())                                                   │
│   459 │   else:                                                                                  │
│ ❱ 460 │   │   raise ValueError("Invalid color type: " + str(color))                              │
│   461                                                                                            │
│   462                                                                                            │
│   463 def color_to_rgba(color: Color | str, alpha: float = 1) -> np.ndarray:                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ValueError: Invalid color type: None
```

<!-- Insert screenshots here (only when absolutely necessary, we prefer copy/pasted output!) -->

</details>


## System specifications

<details><summary>System Details</summary>

- OS:  Ubuntu 21.10
- RAM:  32GB
- Python version (`python/py/python3 --version`):  Python 3.9.7
- Installed modules (provide output from `pip list`):
```
PASTE HERE
```
</details>

<details><summary>LaTeX details</summary>

+ LaTeX distribution (e.g. TeX Live 2020):
+ Installed LaTeX packages:
<!-- output of `tlmgr list --only-installed` for TeX Live or a screenshot of the Packages page for MikTeX -->
</details>

<details><summary>FFMPEG</summary>

Output of `ffmpeg -version`:

```
PASTE HERE
```
</details>

## Additional comments
<!-- Add further context that you think might be relevant for this issue here. -->



Discussion:

Resolving patch:
diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py
--- a/manim/mobject/types/vectorized_mobject.py
+++ b/manim/mobject/types/vectorized_mobject.py
@@ -162,8 +162,8 @@ def generate_rgbas_array(self, color, opacity):
         one color was passed in, a second slightly light color
         will automatically be added for the gradient
         """
-        colors = list(tuplify(color))
-        opacities = list(tuplify(opacity))
+        colors = [c if (c is not None) else BLACK for c in tuplify(color)]
+        opacities = [o if (o is not None) else 0 for o in tuplify(opacity)]
         rgbas = np.array(
             [color_to_rgba(c, o) for c, o in zip(*make_even(colors, opacities))],
         )
@@ -177,9 +177,7 @@ def generate_rgbas_array(self, color, opacity):
         return rgbas
 
     def update_rgbas_array(self, array_name, color=None, opacity=None):
-        passed_color = color if (color is not None) else BLACK
-        passed_opacity = opacity if (opacity is not None) else 0
-        rgbas = self.generate_rgbas_array(passed_color, passed_opacity)
+        rgbas = self.generate_rgbas_array(color, opacity)
         if not hasattr(self, array_name):
             setattr(self, array_name, rgbas)
             return self


Test patch:
diff --git a/tests/test_graphical_units/control_data/mobjects/match_style.npz b/tests/test_graphical_units/control_data/mobjects/match_style.npz
new file mode 100644
Binary files /dev/null and b/tests/test_graphical_units/control_data/mobjects/match_style.npz differ
diff --git a/tests/test_graphical_units/control_data/transform/ReplacementTransform.npz b/tests/test_graphical_units/control_data/transform/ReplacementTransform.npz
new file mode 100644
Binary files /dev/null and b/tests/test_graphical_units/control_data/transform/ReplacementTransform.npz differ
diff --git a/tests/test_graphical_units/test_mobjects.py b/tests/test_graphical_units/test_mobjects.py
--- a/tests/test_graphical_units/test_mobjects.py
+++ b/tests/test_graphical_units/test_mobjects.py
@@ -27,3 +27,12 @@ def test_become(scene):
     s3 = s.copy().become(d3, stretch=True).set_opacity(0.25).set_color(YELLOW)
 
     scene.add(s, d1, d2, d3, s1, s2, s3)
+
+
+@frames_comparison
+def test_match_style(scene):
+    square = Square(fill_color=[RED, GREEN], fill_opacity=1)
+    circle = Circle()
+    VGroup(square, circle).arrange()
+    circle.match_style(square)
+    scene.add(square, circle)
diff --git a/tests/test_graphical_units/test_transform.py b/tests/test_graphical_units/test_transform.py
--- a/tests/test_graphical_units/test_transform.py
+++ b/tests/test_graphical_units/test_transform.py
@@ -155,3 +155,11 @@ def test_MatchPointsScene(scene):
 @frames_comparison(last_frame=False)
 def test_AnimationBuilder(scene):
     scene.play(Square().animate.shift(RIGHT).rotate(PI / 4))
+
+
+@frames_comparison(last_frame=False)
+def test_ReplacementTransform(scene):
+    v1 = Vector()
+    v2 = Vector()
+    v3 = Line()
+    scene.play(ReplacementTransform(VGroup(v1, v2), v3))