Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d46c5df

Browse files
Fix 3d hover coordinates with scaled axes
1 parent f4ce6ba commit d46c5df

2 files changed

Lines changed: 23 additions & 19 deletions

File tree

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,7 @@ def _location_coords(self, xv, yv, renderer):
16531653

16541654
def _get_camera_loc(self):
16551655
"""
1656-
Returns the current camera location in data coordinates.
1656+
Returns the current camera location in transformed coordinates.
16571657
"""
16581658
cx, cy, cz, dx, dy, dz = self._get_w_centers_ranges()
16591659
c = np.array([cx, cy, cz])
@@ -1677,42 +1677,32 @@ def _calc_coord(self, xv, yv, renderer=None):
16771677
else: # perspective projection
16781678
zv = -1 / self._focal_length
16791679

1680-
# Convert point on view plane to transformed coordinates
1681-
# (inv_transform returns scaled coords because M was built with scaled limits)
16821680
p1 = np.array(proj3d.inv_transform(xv, yv, zv, self.invM)).ravel()
16831681

16841682
# Get the vector from the camera to the point on the view plane
1685-
# Camera location is in data space, so transform it to transformed coordinates
1686-
cam_data = self._get_camera_loc()
1687-
cam_scaled = np.array(art3d._apply_scale_transforms(
1688-
cam_data[0], cam_data[1], cam_data[2], self)).ravel()
1689-
vec = cam_scaled - p1
1690-
1691-
# Get the pane locations for each of the axes in data space
1692-
# and transform to transformed coordinates
1683+
vec = self._get_camera_loc() - p1
1684+
1685+
# Get the pane locations for each of the axes
16931686
pane_locs_data = []
16941687
for axis in self._axis_map.values():
16951688
xys, loc = axis.active_pane()
16961689
pane_locs_data.append(loc)
1697-
pane_locs_scaled = np.array(art3d._apply_scale_transforms(
1698-
pane_locs_data[0], pane_locs_data[1], pane_locs_data[2], self)).ravel()
16991690

17001691
# Find the distance to the nearest pane by projecting the view vector
17011692
scales = np.zeros(3)
17021693
for i in range(3):
17031694
if vec[i] == 0:
17041695
scales[i] = np.inf
17051696
else:
1706-
scales[i] = (p1[i] - pane_locs_scaled[i]) / vec[i]
1697+
scales[i] = (pane_locs_data[i] - p1[i]) / vec[i]
17071698
pane_idx = np.argmin(abs(scales))
17081699
scale = scales[pane_idx]
17091700

1710-
# Calculate the point on the closest pane in transformed coordinates
1711-
p2_scaled = p1 - scale*vec
1701+
# Calculate the point on the closest pane
1702+
p2 = p1 + scale * vec
17121703

1713-
# Convert back to data coordinates
1714-
p2 = np.array(self._untransform_point(
1715-
p2_scaled[0], p2_scaled[1], p2_scaled[2]))
1704+
# Convert from transformed to data coordinates
1705+
p2 = np.array(self._untransform_point(p2[0], p2[1], p2[2]))
17161706
return p2, pane_idx
17171707

17181708
def _arcball(self, x: float, y: float) -> np.ndarray:

lib/mpl_toolkits/mplot3d/tests/test_axes3d.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,3 +3171,17 @@ def test_scale3d_autoscale_with_log():
31713171
('z', ax.get_zlim())]:
31723172
assert lim[0] > 0, f"{name} lower limit should be positive"
31733173
assert lim[1] > 0, f"{name} upper limit should be positive"
3174+
3175+
3176+
def test_scale3d_calc_coord():
3177+
"""_calc_coord should return data coordinates with correct pane values."""
3178+
fig = plt.figure()
3179+
ax = fig.add_subplot(projection='3d')
3180+
ax.scatter([1, 10, 100], [1, 10, 100], [1, 10, 100])
3181+
ax.set(xscale='log', yscale='log', zscale='log')
3182+
fig.canvas.draw()
3183+
3184+
point, pane_idx = ax._calc_coord(0.5, 0.5)
3185+
# Pane coordinate should match axis limit (y-pane at max)
3186+
assert pane_idx == 1
3187+
assert point[pane_idx] == pytest.approx(ax.get_ylim()[1])

0 commit comments

Comments
 (0)