Repository: ManimCommunity/manim

Issue:
ThreeDScene.move_camera() results in NotImplementedError
Commit 62050bbb04a1f8e481972e1db36f2634dfbae425 changes the `pass` statements of some methods in `Mobject()` into `NotImplementedError` .

This causes the `move_camera` method in a `ThreeDScene` or `SpecialThreeDScene` to fail, throwing a `NotImplementedError`, as it uses the `interpolate_color` method of `Mobject`.

```py
from manim import *

class TestScene(SpecialThreeDScene):
    def construct(self):
        self.move_camera(
            **self.default_angled_camera_position,
            run_time=1,
        )
```

The snippet above triggers the NotImplementedError in the `interpolate_color` method of `Mobject()`

This could be fixed by reverting the NotImplementedError of the `interpolate_color` method back into the `pass` statement that it originally was.

I think it would also prove fruitful if the methods `become_partial` and `pointwise_become_partial` also just had `pass` statements as they could also result in another method somewhere else not working properly.
ThreeDScene.move_camera() results in NotImplementedError
Commit 62050bbb04a1f8e481972e1db36f2634dfbae425 changes the `pass` statements of some methods in `Mobject()` into `NotImplementedError` .

This causes the `move_camera` method in a `ThreeDScene` or `SpecialThreeDScene` to fail, throwing a `NotImplementedError`, as it uses the `interpolate_color` method of `Mobject`.

```py
from manim import *

class TestScene(SpecialThreeDScene):
    def construct(self):
        self.move_camera(
            **self.default_angled_camera_position,
            run_time=1,
        )
```

The snippet above triggers the NotImplementedError in the `interpolate_color` method of `Mobject()`

This could be fixed by reverting the NotImplementedError of the `interpolate_color` method back into the `pass` statement that it originally was.

I think it would also prove fruitful if the methods `become_partial` and `pointwise_become_partial` also just had `pass` statements as they could also result in another method somewhere else not working properly.


Discussion:
Wait so this snippet is calling `interpolate_color` which is currently set to raise a `NotImplementedError`?

The fix then should be to make a decision as to whether or not call that function, instead of calling a function that does nothing, no?
In hindsight, yeah, that would be the right solution.

I've removed the methods that must be implemented in subclasses and made manim only call `interpolate_color` if the Mobject has such a method. I'll test it some more and make a PR in some hours time.
I think it is possible to keep `NotImplementedError` for these methods of `Mobject`, but write these methods for all its subclasses, and just treat `Mobject` as a similar abstract class, which will be more clear.

Now only `ValueTracker` is a direct subclass of `Mobject`, so you can write `interpolate_color` or `interpolate` methods for `ValueTracker`, which can solve this problem and make the code clearer.
> Now only `ValueTracker` is a direct subclass of `Mobject`

`VMobject`, `PMobject`, `ImageMobject` are also direct subclasses of it.

These are the only ones with custom `interpolate_color` method.
> `VMobject`, `PMobject`, `ImageMobject` are also direct subclasses of it.
> 
> These are the only ones with custom `interpolate_color` method.

I mean `ValueTracker` is the only subclass that directly inherits from Mobject, **but does not implement these methods.** 
While other `VMobject`, `PMobject`, `ImageMobject` have implemented `interpolate` method or `interpolate_color` method. So just implement the `interpolate` method for `ValueTracker`.
Why should ValueTracker even have an `interpolate_color` method? It isn't a coloured Mobject right?

I think the best way would be to remove the methods that need to be implemented by children, and only use those methods if the child has them.
I say `interpolate` method which to interpolate between two `ValueTracker`, not `interpolate_color`. 
If `ValueTracker` has `interpolate` method, it won't call the `interpolate_color` method, and there is actually no use of `interpolate_color` for `ValueTracker`.
Isn't this better.
Oh, I see what you mean. That's a better way.

Also, this is slightly unrelated, but I found that the method `become_partial` is not mentioned anywhere in the code other than as its definition in Mobject. Should it be removed outright?
Yes, `become_partial` is really useless because its function may be the same as `pointwise_become_partial`, and the latter is implemented by subclass.
Wait so this snippet is calling `interpolate_color` which is currently set to raise a `NotImplementedError`?

The fix then should be to make a decision as to whether or not call that function, instead of calling a function that does nothing, no?
In hindsight, yeah, that would be the right solution.

I've removed the methods that must be implemented in subclasses and made manim only call `interpolate_color` if the Mobject has such a method. I'll test it some more and make a PR in some hours time.
I think it is possible to keep `NotImplementedError` for these methods of `Mobject`, but write these methods for all its subclasses, and just treat `Mobject` as a similar abstract class, which will be more clear.

Now only `ValueTracker` is a direct subclass of `Mobject`, so you can write `interpolate_color` or `interpolate` methods for `ValueTracker`, which can solve this problem and make the code clearer.
> Now only `ValueTracker` is a direct subclass of `Mobject`

`VMobject`, `PMobject`, `ImageMobject` are also direct subclasses of it.

These are the only ones with custom `interpolate_color` method.
> `VMobject`, `PMobject`, `ImageMobject` are also direct subclasses of it.
> 
> These are the only ones with custom `interpolate_color` method.

I mean `ValueTracker` is the only subclass that directly inherits from Mobject, **but does not implement these methods.** 
While other `VMobject`, `PMobject`, `ImageMobject` have implemented `interpolate` method or `interpolate_color` method. So just implement the `interpolate` method for `ValueTracker`.
Why should ValueTracker even have an `interpolate_color` method? It isn't a coloured Mobject right?

I think the best way would be to remove the methods that need to be implemented by children, and only use those methods if the child has them.
I say `interpolate` method which to interpolate between two `ValueTracker`, not `interpolate_color`. 
If `ValueTracker` has `interpolate` method, it won't call the `interpolate_color` method, and there is actually no use of `interpolate_color` for `ValueTracker`.
Isn't this better.
Oh, I see what you mean. That's a better way.

Also, this is slightly unrelated, but I found that the method `become_partial` is not mentioned anywhere in the code other than as its definition in Mobject. Should it be removed outright?
Yes, `become_partial` is really useless because its function may be the same as `pointwise_become_partial`, and the latter is implemented by subclass.

Resolving patch:
diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py
--- a/manim/mobject/mobject.py
+++ b/manim/mobject/mobject.py
@@ -1088,17 +1088,6 @@ def interpolate(self, mobject1, mobject2,
     def interpolate_color(self, mobject1, mobject2, alpha):
         raise NotImplementedError('Please override in a child class.')
 
-    def become_partial(self, mobject, a, b):
-        """
-        Set points in such a way as to become only
-        part of mobject.
-        Inputs 0 <= a < b <= 1 determine what portion
-        of mobject to become.
-        """
-        raise NotImplementedError('Please override in a child class.')
-
-        # TODO, color?
-
     def pointwise_become_partial(self, mobject, a, b):
         raise NotImplementedError('Please override in a child class.')
 
@@ -1120,7 +1109,7 @@ def throw_error_if_no_points(self):
                       "for a Mobject with no points"
             caller_name = sys._getframe(1).f_code.co_name
             raise Exception(message.format(caller_name))
-    
+
     # About z-index
     def set_z_index(self, z_index_value):
         """Sets the mobject's :attr:`z_index` to the value specified in `z_index_value`.
@@ -1129,7 +1118,7 @@ def set_z_index(self, z_index_value):
         ----------
         z_index_value : Union[:class:`int`, :class:`float`]
             The new value of :attr:`z_index` set.
-        
+
         Returns
         -------
         :class:`Mobject`
@@ -1137,10 +1126,10 @@ def set_z_index(self, z_index_value):
         """
         self.z_index = z_index_value
         return self
-    
+
     def set_z_index_by_z_coordinate(self):
         """Sets the mobject's z coordinate to the value of :attr:`z_index`.
-        
+
         Returns
         -------
         :class:`Mobject`
diff --git a/manim/mobject/value_tracker.py b/manim/mobject/value_tracker.py
--- a/manim/mobject/value_tracker.py
+++ b/manim/mobject/value_tracker.py
@@ -1,11 +1,12 @@
 import numpy as np
 
+from ..utils.paths import straight_path
 from ..mobject.mobject import Mobject
 
 
 class ValueTracker(Mobject):
     """
-    Note meant to be displayed.  Instead the position encodes some
+    Not meant to be displayed.  Instead the position encodes some
     number, often one which another animation or continual_animation
     uses for its update function, and by treating it as a mobject it can
     still be animated and manipulated just like anything else.
@@ -26,6 +27,17 @@ def set_value(self, value):
     def increment_value(self, d_value):
         self.set_value(self.get_value() + d_value)
 
+    def interpolate(self, mobject1, mobject2,
+                    alpha, path_func=straight_path):
+        """
+        Turns self into an interpolation between mobject1
+        and mobject2.
+        """
+        self.points = path_func(
+            mobject1.points, mobject2.points, alpha
+        )
+        return self
+
 
 class ExponentialValueTracker(ValueTracker):
     """


Test patch: