Repository: manimcommunity/manim
Issue: z-axis and parametric surface misplaced in ThreeDAxes

## Description of bug / unexpected behavior
<!-- Add a clear and concise description of the problem you encountered. -->
When using `ThreeDAxes` in v0.6.0 to create a plot where the minimum values of the x-axis and y-axis are not 0, the z-axis is not adjusted to go through where the x-axis and y-axis cross.  Meanwhile, any parametric surface added to the plot is also not moved to account for the shift in the x-axis and y-axis.  Here is an example:

https://user-images.githubusercontent.com/79891353/116828508-0c7c3000-ab54-11eb-9bb6-03411961d5df.mp4

## Expected behavior
<!-- Add a clear and concise description of what you expected to happen. -->
The z-axis should automatically adjust, just as the x-axis and y-axis both adjust according to the `x_range` and `y_range` variables.  Likewise, when adding a parametric surface, or any `mobject` to the axes, it too should be adjusted to the correct position.

## 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 ThreeDSurfacePlot(ThreeDScene):
    def construct(self):
        resolution_fa = 42
        self.set_camera_orientation(phi=75 * DEGREES, theta=10 * DEGREES)
        
        axes = ThreeDAxes(
                x_range=(5, 10, 1),
                y_range=(3, 8, 1),
                z_range=(-1, 1, 0.5)
                )

        def param_surface(u, v):
            x = u
            y = v
            z = np.sin(x) * np.cos(y)
            return z

        surface_plane = ParametricSurface(
            lambda u, v: axes.c2p(u, v, param_surface(u, v)),
            resolution=(resolution_fa, resolution_fa),
            v_min=5,
            v_max=10,
            u_min=3,
            u_max=8,
        )

        surface_plane.set_style(fill_opacity=1, stroke_color=GREEN)
        surface_plane.set_fill_by_checkerboard(ORANGE, BLUE, opacity=0.5)
                                    
        self.add(axes, surface_plane)
        
        self.begin_ambient_camera_rotation(rate=-0.3)
        self.wait(10)
```

</details>


## System specifications

<details><summary>System Details</summary>
Manim v0.6.0
</details>


## Additional comments
<!-- Add further context that you think might be relevant for this issue here. -->
I will try to investigate this issue and report back my findings.

Changed files:
manim/mobject/coordinate_systems.py, tests/test_axes_shift.py

diff --git a/manim/mobject/coordinate_systems.py b/manim/mobject/coordinate_systems.py
index 629cd605..aac569a4 100644
--- a/manim/mobject/coordinate_systems.py
+++ b/manim/mobject/coordinate_systems.py
@@ -5,7 +5,7 @@ __all__ = ["CoordinateSystem", "Axes", "ThreeDAxes", "NumberPlane", "ComplexPlan
 
 import math
 import numbers
-from typing import Iterable, Optional, Sequence
+from typing import Iterable, List, Optional, Sequence
 
 import numpy as np
 
@@ -246,18 +246,13 @@ class Axes(VGroup, CoordinateSystem):
         new_config["length"] = length
         axis = NumberLine(range_terms, **new_config)
 
-        # without the if/elif, graph does not exist when min > 0 or max < 0
+        # without the call to origin_shift, graph does not exist when min > 0 or max < 0
         # shifts the axis so that 0 is centered
-        if range_terms[0] > 0:
-            axis.shift(-axis.number_to_point(range_terms[0]))
-        elif range_terms[1] < 0:
-            axis.shift(-axis.number_to_point(range_terms[1]))
-        else:
-            axis.shift(-axis.number_to_point(0))
+        axis.shift(-axis.number_to_point(self.origin_shift(range_terms)))
         return axis
 
     def coords_to_point(self, *coords):
-        origin = self.x_axis.number_to_point(0)
+        origin = self.x_axis.number_to_point(self.origin_shift(self.x_range))
         result = np.array(origin)
         for axis, coord in zip(self.get_axes(), coords):
             result += axis.number_to_point(coord) - origin
@@ -367,6 +362,22 @@ class Axes(VGroup, CoordinateSystem):
 
         return line_graph
 
+    @staticmethod
+    def origin_shift(axis_range: List[float]) -> float:
+        """Determines how to shift graph mobjects to compensate when 0 is not on the axis.
+
+        Parameters
+        ----------
+        axis_range
+            The range of the axis : ``(x_min, x_max, x_step)``.
+        """
+        if axis_range[0] > 0:
+            return axis_range[0]
+        if axis_range[1] < 0:
+            return axis_range[1]
+        else:
+            return 0
+
 
 class ThreeDAxes(Axes):
     """A 3-dimensional set of axes.
@@ -444,7 +455,7 @@ class ThreeDAxes(Axes):
         z_axis = self.create_axis(self.z_range, self.z_axis_config, self.z_length)
         z_axis.rotate_about_zero(-PI / 2, UP)
         z_axis.rotate_about_zero(angle_of_vector(self.z_normal))
-        z_axis.shift(self.x_axis.n2p(0))
+        z_axis.shift(self.x_axis.number_to_point(self.origin_shift(x_range)))
 
         self.axes.add(z_axis)
         self.add(z_axis)
diff --git a/tests/test_axes_shift.py b/tests/test_axes_shift.py
index 6cf996e3..cc336258 100644
--- a/tests/test_axes_shift.py
+++ b/tests/test_axes_shift.py
@@ -1,6 +1,7 @@
 import numpy as np
 import pytest
 
+from manim.mobject.coordinate_systems import Axes
 from manim.scene.graph_scene import GraphScene
 
 
@@ -42,3 +43,9 @@ def test_axes_with_xy_shift():
     G.setup_axes()
     assert all(np.isclose(G.graph_origin, G.x_axis.n2p(1)))
     assert all(np.isclose(G.graph_origin, G.y_axis.n2p(-5)))
+
+
+def test_axes_origin_shift():
+    ax = Axes(x_range=(5, 10, 1), y_range=(40, 45, 0.5))
+    assert np.allclose(ax.coords_to_point(5, 40), ax.x_axis.number_to_point(5))
+    assert np.allclose(ax.coords_to_point(5, 40), ax.y_axis.number_to_point(40))