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

Skip to content

Commit 0fb87fc

Browse files
Have zoom and pan work with 3D log scales
1 parent 1afb165 commit 0fb87fc

1 file changed

Lines changed: 56 additions & 14 deletions

File tree

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,16 +1887,33 @@ def drag_pan(self, button, key, x, y):
18871887
R = -R / self._box_aspect * self._dist
18881888
duvw_projected = R.T @ np.array([du, dv, dw])
18891889

1890-
# Calculate pan distance
1891-
minx, maxx, miny, maxy, minz, maxz = self.get_w_lims()
1890+
# Calculate pan distance in scaled space for proper non-linear scale handling
1891+
minx, maxx, miny, maxy, minz, maxz = self._get_scaled_limits()
18921892
dx = (maxx - minx) * duvw_projected[0]
18931893
dy = (maxy - miny) * duvw_projected[1]
18941894
dz = (maxz - minz) * duvw_projected[2]
18951895

1896+
# Compute new limits in scaled space
1897+
new_xmin_scaled = minx + dx
1898+
new_xmax_scaled = maxx + dx
1899+
new_ymin_scaled = miny + dy
1900+
new_ymax_scaled = maxy + dy
1901+
new_zmin_scaled = minz + dz
1902+
new_zmax_scaled = maxz + dz
1903+
1904+
# Transform back to data space
1905+
x_inv = self.xaxis.get_transform().inverted()
1906+
y_inv = self.yaxis.get_transform().inverted()
1907+
z_inv = self.zaxis.get_transform().inverted()
1908+
1909+
new_xmin, new_xmax = x_inv.transform([new_xmin_scaled, new_xmax_scaled])
1910+
new_ymin, new_ymax = y_inv.transform([new_ymin_scaled, new_ymax_scaled])
1911+
new_zmin, new_zmax = z_inv.transform([new_zmin_scaled, new_zmax_scaled])
1912+
18961913
# Set the new axis limits
1897-
self.set_xlim3d(minx + dx, maxx + dx, auto=None)
1898-
self.set_ylim3d(miny + dy, maxy + dy, auto=None)
1899-
self.set_zlim3d(minz + dz, maxz + dz, auto=None)
1914+
self.set_xlim3d(new_xmin, new_xmax, auto=None)
1915+
self.set_ylim3d(new_ymin, new_ymax, auto=None)
1916+
self.set_zlim3d(new_zmin, new_zmax, auto=None)
19001917

19011918
def _calc_view_axes(self, eye):
19021919
"""
@@ -2012,6 +2029,9 @@ def _scale_axis_limits(self, scale_x, scale_y, scale_z):
20122029
limits by scale factors. A scale factor > 1 zooms out and a scale
20132030
factor < 1 zooms in.
20142031
2032+
For non-linear scales, the scaling happens in scaled space to ensure
2033+
uniform zoom behavior.
2034+
20152035
Parameters
20162036
----------
20172037
scale_x : float
@@ -2021,23 +2041,45 @@ def _scale_axis_limits(self, scale_x, scale_y, scale_z):
20212041
scale_z : float
20222042
Scale factor for the z data axis.
20232043
"""
2024-
# Get the axis centers and ranges
2044+
# Get the axis centers and ranges (in scaled space for non-linear scales)
20252045
cx, cy, cz, dx, dy, dz = self._get_w_centers_ranges()
20262046

2027-
# Set the scaled axis limits
2028-
self.set_xlim3d(cx - dx*scale_x/2, cx + dx*scale_x/2, auto=None)
2029-
self.set_ylim3d(cy - dy*scale_y/2, cy + dy*scale_y/2, auto=None)
2030-
self.set_zlim3d(cz - dz*scale_z/2, cz + dz*scale_z/2, auto=None)
2047+
# Compute new limits in scaled space
2048+
new_xmin_scaled = cx - dx*scale_x/2
2049+
new_xmax_scaled = cx + dx*scale_x/2
2050+
new_ymin_scaled = cy - dy*scale_y/2
2051+
new_ymax_scaled = cy + dy*scale_y/2
2052+
new_zmin_scaled = cz - dz*scale_z/2
2053+
new_zmax_scaled = cz + dz*scale_z/2
2054+
2055+
# Transform back to data space
2056+
x_inv = self.xaxis.get_transform().inverted()
2057+
y_inv = self.yaxis.get_transform().inverted()
2058+
z_inv = self.zaxis.get_transform().inverted()
2059+
2060+
new_xmin, new_xmax = x_inv.transform([new_xmin_scaled, new_xmax_scaled])
2061+
new_ymin, new_ymax = y_inv.transform([new_ymin_scaled, new_ymax_scaled])
2062+
new_zmin, new_zmax = z_inv.transform([new_zmin_scaled, new_zmax_scaled])
2063+
2064+
# Set the new axis limits
2065+
self.set_xlim3d(new_xmin, new_xmax, auto=None)
2066+
self.set_ylim3d(new_ymin, new_ymax, auto=None)
2067+
self.set_zlim3d(new_zmin, new_zmax, auto=None)
20312068

20322069
def _get_w_centers_ranges(self):
2033-
"""Get 3D world centers and axis ranges."""
2034-
# Calculate center of axis limits
2035-
minx, maxx, miny, maxy, minz, maxz = self.get_w_lims()
2070+
"""
2071+
Get 3D world centers and axis ranges in scaled space.
2072+
2073+
For non-linear scales (log, symlog, etc.), centers and ranges are
2074+
computed in scaled coordinates to ensure uniform zoom/pan behavior.
2075+
"""
2076+
# Get limits in scaled space for proper zoom/pan with non-linear scales
2077+
minx, maxx, miny, maxy, minz, maxz = self._get_scaled_limits()
20362078
cx = (maxx + minx)/2
20372079
cy = (maxy + miny)/2
20382080
cz = (maxz + minz)/2
20392081

2040-
# Calculate range of axis limits
2082+
# Calculate range of axis limits in scaled space
20412083
dx = (maxx - minx)
20422084
dy = (maxy - miny)
20432085
dz = (maxz - minz)

0 commit comments

Comments
 (0)