class_docstr: Camera implementing 2D pan/zoom mouse interaction.
  
  For this camera, the ``scale_factor`` indicates the zoom level, and
  the ``center`` indicates the center position of the view.
  
  By default, this camera inverts the y axis of the scene. This usually
  results in the scene +y axis pointing upward because widgets (including
  ViewBox) have their +y axis pointing downward.
  
  Parameters
  ----------
  rect : Rect
      A Rect object or 4-element tuple that specifies the rectangular
      area to show.
  aspect : float | None
      The aspect ratio (i.e. scaling) between x and y dimension of
      the scene. E.g. to show a square image as square, the aspect
      should be 1. If None (default) the x and y dimensions are scaled
      independently.
  **kwargs : dict
      Keyword arguments to pass to `BaseCamera`.
  
  Notes
  -----
  Interaction:
  
      * LMB: pan the view
      * RMB or scroll: zooms the view
class_docstr_tok: ["Camera","implementing","2D","pan\/zoom","mouse","interaction",".","For","this","camera",",","the","``","scale_factor","``","indicates","the","zoom","level",",","and","the","``","center","``","indicates","the","center","position","of","the","view",".","By","default",",","this","camera","inverts","the","y","axis","of","the","scene",".","This","usually","results","in","the","scene","+y","axis","pointing","upward","because","widgets","(","including","ViewBox",")","have","their","+y","axis","pointing","downward",".","Parameters","--","--","--","--","--","rect",":","Rect","A","Rect","object","or","4-element","tuple","that","specifies","the","rectangular","area","to","show",".","aspect",":","float","|","None","The","aspect","ratio","(","i.e",".","scaling",")","between","x","and","y","dimension","of","the","scene",".","E.g",".","to","show","a","square","image","as","square",",","the","aspect","should","be","1",".","If","None","(","default",")","the","x","and","y","dimensions","are","scaled","independently",".","*","*","kwargs",":","dict","Keyword","arguments","to","pass","to","`","BaseCamera","`",".","Notes","--","--","-","Interaction",":","*","LMB",":","pan","the","view","*","RMB","or","scroll",":","zooms","the","view"]
code: def _update_transform(self):
      rect = self.rect
      self._real_rect = Rect(rect)
      vbr = self._viewbox.rect.flipped(
          x=self.flip[0], y=(not self.flip[1])
      )
      d = self.depth_value
  
      # apply scale ratio constraint
      if self._aspect is not None:
          # Aspect ratio of the requested range
          requested_aspect = (
              rect.width / rect.height if rect.height != 0 else 1
          )
          # Aspect ratio of the viewbox
          view_aspect = vbr.width / vbr.height if vbr.height != 0 else 1
          # View aspect ratio needed to obey the scale constraint
          constrained_aspect = abs(view_aspect / self._aspect)
  
          if requested_aspect > constrained_aspect:
              # view range needs to be taller than requested
              dy = 0.5 * (rect.width / constrained_aspect - rect.height)
              self._real_rect.top += dy
              self._real_rect.bottom -= dy
          else:
              # view range needs to be wider than requested
              dx = 0.5 * (rect.height * constrained_aspect - rect.width)
              self._real_rect.left -= dx
              self._real_rect.right += dx
  
      # Apply mapping between viewbox and cam view
      self.transform.set_mapping(self._real_rect, vbr, update=False)
      # Scale z, so that the clipping planes are between -alot and +alot
      self.transform.zoom((1, 1, 1 / d))
  
      # We've now set self.transform, which represents our 2D
      # transform When up is +z this is all. In other cases,
      # self.transform is now set up correctly to allow pan/zoom, but
      # for the scene we need a different (3D) mapping. When there
      # is a minus in up, we simply look at the scene from the other
      # side (as if z was flipped).
      if self.up == "+z":
          self.tf_mat.matrix = self.transform.as_matrix().matrix
      else:
          rr = self._real_rect
          d = d if (self.up[0] == "+") else -d
          pp1 = [
              (vbr.left, vbr.bottom, 0),
              (vbr.left, vbr.top, 0),
              (vbr.right, vbr.bottom, 0),
              (vbr.left, vbr.bottom, 1),
          ]
          # Get Mapping
          if self.up[1] == "z":
              pp2 = [
                  (rr.left, rr.bottom, 0),
                  (rr.left, rr.top, 0),
                  (rr.right, rr.bottom, 0),
                  (rr.left, rr.bottom, d),
              ]
          elif self.up[1] == "y":
              pp2 = [
                  (rr.left, 0, rr.bottom),
                  (rr.left, 0, rr.top),
                  (rr.right, 0, rr.bottom),
                  (rr.left, d, rr.bottom),
              ]
          elif self.up[1] == "x":
              pp2 = [
                  (0, rr.left, rr.bottom),
                  (0, rr.left, rr.top),
                  (0, rr.right, rr.bottom),
                  (d, rr.left, rr.bottom),
              ]
  
          # Apply
          self.tf_mat.set_mapping(np.array(pp2), np.array(pp1))
  
      # Set on viewbox
      self._set_scene_transform(self.tf_mat)
  
imports: from __future__ import division
  import numpy
  from .base_camera import BaseCamera
  from ...geometry import Rect
  from ...visuals.transforms import STTransform, MatrixTransform
label_desc: Use image node_id 13 for calling the PanZoomCamera obj's underlying member method code with example usage: obj._update_transform() without return types