@@ -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