Skip to content

Commit c924c66

Browse files
authored
better plot scaling logic (#938)
* better plot scaling logic for when a subplot controller manages multiple cameras * skip scaling in empty subplots
1 parent 3e8b8d5 commit c924c66

File tree

1 file changed

+62
-18
lines changed

1 file changed

+62
-18
lines changed

fastplotlib/layouts/_plot_area.py

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -607,14 +607,33 @@ def center_scene(self, *, zoom: float = 1.0):
607607
if not len(self._fpl_graphics_scene.children) > 0:
608608
return
609609

610-
# scale all cameras associated with this controller
611-
# else it looks wonky
612-
for camera in self.controller.cameras:
613-
camera.show_object(self._fpl_graphics_scene)
610+
if self.parent.__class__.__name__.endswith("Figure"):
611+
# always use figure._subplots.ravel() in internal fastplotlib code
612+
# otherwise if we use `for subplot in figure`, this could conflict
613+
# with a user's iterator where they are doing `for subplot in figure` !!!
614+
for subplot in self.parent._subplots.ravel():
615+
# scale all cameras associated with this controller
616+
if subplot.camera in self.controller.cameras:
617+
# skip if the scene is empty
618+
if len(subplot._fpl_graphics_scene.children) < 1:
619+
continue
620+
621+
# center the camera in the other subplot w.r.t. the scene in that other subplot!
622+
self._auto_center_scene(
623+
subplot.camera, subplot._fpl_graphics_scene, zoom
624+
)
625+
else:
626+
# just change for this plot area
627+
# this is probably a dock area
628+
self._auto_center_scene(self.camera, self._fpl_graphics_scene, zoom)
614629

615-
# camera.show_object can cause the camera width and height to increase so apply a zoom to compensate
616-
# probably because camera.show_object uses bounding sphere
617-
camera.zoom = zoom
630+
def _auto_center_scene(
631+
self, camera: pygfx.PerspectiveCamera, scene: pygfx.Scene, zoom: float
632+
):
633+
camera.show_object(scene)
634+
# camera.show_object can cause the camera width and height to increase so apply a zoom to compensate
635+
# probably because camera.show_object uses bounding sphere
636+
camera.zoom = zoom
618637

619638
def auto_scale(
620639
self,
@@ -642,16 +661,43 @@ def auto_scale(
642661
self.center_scene()
643662

644663
if maintain_aspect is None: # if not provided keep current setting
664+
# use the same maintain apsect for all other cameras that this controller manages
665+
# I think this make sense for most use cases, even when the other controllers are
666+
# only managing one or 2 axes
645667
maintain_aspect = self.camera.maintain_aspect
646668

647-
# scale all cameras associated with this controller else it looks wonky
648-
for camera in self.controller.cameras:
649-
camera.maintain_aspect = maintain_aspect
669+
if self.parent.__class__.__name__.endswith("Figure"):
670+
# always use figure._subplots.ravel() in internal fastplotlib code
671+
# otherwise if we use `for subplot in figure`, this could conflict
672+
# with a user's iterator where they are doing `for subplot in figure` !!!
673+
for subplot in self.parent._subplots.ravel():
674+
# skip if the scene is empty
675+
if len(subplot._fpl_graphics_scene.children) < 1:
676+
continue
650677

651-
if len(self._fpl_graphics_scene.children) > 0:
652-
width, height, depth = np.ptp(
653-
self._fpl_graphics_scene.get_world_bounding_box(), axis=0
678+
# scale the camera in the other subplot w.r.t. the scene in that other subplot!
679+
if subplot.camera in self.controller.cameras:
680+
camera = subplot.camera
681+
self._auto_scale_scene(
682+
camera, subplot._fpl_graphics_scene, zoom, maintain_aspect
683+
)
684+
else:
685+
# just change for this plot area, this is probably a dock area
686+
self._auto_scale_scene(
687+
self.camera, self._fpl_graphics_scene, zoom, maintain_aspect
654688
)
689+
690+
def _auto_scale_scene(
691+
self,
692+
camera: pygfx.PerspectiveCamera,
693+
scene: pygfx.Scene,
694+
zoom: float,
695+
maintain_aspect: bool,
696+
):
697+
camera.maintain_aspect = maintain_aspect
698+
699+
if len(scene.children) > 0:
700+
width, height, depth = np.ptp(scene.get_world_bounding_box(), axis=0)
655701
else:
656702
width, height, depth = (1, 1, 1)
657703

@@ -661,12 +707,10 @@ def auto_scale(
661707
if height < 0.01:
662708
height = 1
663709

664-
# scale all cameras associated with this controller else it looks wonky
665-
for camera in self.controller.cameras:
666-
camera.width = width
667-
camera.height = height
710+
camera.width = width
711+
camera.height = height
668712

669-
camera.zoom = zoom
713+
camera.zoom = zoom
670714

671715
def remove_graphic(self, graphic: Graphic):
672716
"""

0 commit comments

Comments
 (0)