class_docstr: **Bases:** :class:`object`
  
  Abstract class providing useful methods to GraphicsObject and GraphicsWidget.
  (This is required because we cannot have multiple inheritance with QObject subclasses.)
  
  A note about Qt's GraphicsView framework:
  
  The GraphicsView system places a lot of emphasis on the notion that the graphics within the scene should be device independent--you should be able to take the same graphics and display them on screens of different resolutions, printers, export to SVG, etc. This is nice in principle, but causes me a lot of headache in practice. It means that I have to circumvent all the device-independent expectations any time I want to operate in pixel coordinates rather than arbitrary scene coordinates. A lot of the code in GraphicsItem is devoted to this task--keeping track of view widgets and device transforms, computing the size and shape of a pixel in local item coordinates, etc. Note that in item coordinates, a pixel does not have to be square or even rectangular, so just asking how to increase a bounding rect by 2px can be a rather complex task.
docstr: Return vectors in local coordinates representing the width and height of a view pixel.
  If direction is specified, then return vectors parallel and orthogonal to it.
  
  Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
  or if pixel size is below floating-point precision limit.
docstr_tok: ["Return","vectors","in","local","coordinates","representing","the","width","and","height","of","a","view","pixel",".","If","direction","is","specified",",","then","return","vectors","parallel","and","orthogonal","to","it",".","Return","(","None",",","None",")","if","pixel","size","is","not","yet","defined","(","usually","because","the","item","has","not","yet","been","displayed",")","or","if","pixel","size","is","below","floating-point","precision","limit","."]
code: def pixelVectors(self, direction=None):
      """Return vectors in local coordinates representing the width and height of a view pixel.
      If direction is specified, then return vectors parallel and orthogonal to it.
  
      Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
      or if pixel size is below floating-point precision limit.
      """
  
      ## This is an expensive function that gets called very frequently.
      ## We have two levels of cache to try speeding things up.
  
      dt = self.deviceTransform()
      if dt is None:
          return None, None
  
      ## Ignore translation. If the translation is much larger than the scale
      ## (such as when looking at unix timestamps), we can get floating-point errors.
      dt.setMatrix(
          dt.m11(), dt.m12(), 0, dt.m21(), dt.m22(), 0, 0, 0, 1
      )
  
      if direction is None:
          direction = QtCore.QPointF(1, 0)
      elif direction.manhattanLength() == 0:
          raise Exception(
              "Cannot compute pixel length for 0-length vector."
          )
  
      key = (
          dt.m11(),
          dt.m21(),
          dt.m12(),
          dt.m22(),
          direction.x(),
          direction.y(),
      )
  
      ## check local cache
      if key == self._pixelVectorCache[0]:
          return tuple(
              map(Point, self._pixelVectorCache[1])
          )  ## return a *copy*
  
      ## check global cache
      pv = self._pixelVectorGlobalCache.get(key, None)
      if pv is not None:
          self._pixelVectorCache = [key, pv]
          return tuple(map(Point, pv))  ## return a *copy*
  
      ## attempt to re-scale direction vector to fit within the precision of the coordinate system
      ## Here's the problem: we need to map the vector 'direction' from the item to the device, via transform 'dt'.
      ## In some extreme cases, this mapping can fail unless the length of 'direction' is cleverly chosen.
      ## Example:
      ##   dt = [ 1, 0,    2
      ##          0, 2, 1e20
      ##          0, 0,    1 ]
      ## Then we map the origin (0,0) and direction (0,1) and get:
      ##    o' = 2,1e20
      ##    d' = 2,1e20  <-- should be 1e20+2, but this can't be represented with a 32-bit float
      ##
      ##    |o' - d'|  == 0    <-- this is the problem.
  
      ## Perhaps the easiest solution is to exclude the transformation column from dt. Does this cause any other problems?
  
      # if direction.x() == 0:
      # r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
      ##r = 1.0/(abs(dt.m12()) + abs(dt.m22()))
      # elif direction.y() == 0:
      # r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
      ##r = 1.0/(abs(dt.m11()) + abs(dt.m21()))
      # else:
      # r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
      # if r == 0:
      # r = 1.  ## shouldn't need to do this; probably means the math above is wrong?
      # directionr = direction * r
      directionr = direction
  
      ## map direction vector onto device
      # viewDir = Point(dt.map(directionr) - dt.map(Point(0,0)))
      # mdirection = dt.map(directionr)
      dirLine = QtCore.QLineF(QtCore.QPointF(0, 0), directionr)
      viewDir = dt.map(dirLine)
      if viewDir.length() == 0:
          return (
              None,
              None,
          )  ##  pixel size cannot be represented on this scale
  
      ## get unit vector and orthogonal vector (length of pixel)
      # orthoDir = Point(viewDir[1], -viewDir[0])  ## orthogonal to line in pixel-space
      try:
          normView = viewDir.unitVector()
          # normView = viewDir.norm()  ## direction of one pixel orthogonal to line
          normOrtho = normView.normalVector()
          # normOrtho = orthoDir.norm()
      except:
          raise Exception("Invalid direction %s" % directionr)
  
      ## map back to item
      dti = fn.invertQTransform(dt)
      # pv = Point(dti.map(normView)-dti.map(Point(0,0))), Point(dti.map(normOrtho)-dti.map(Point(0,0)))
      pv = Point(dti.map(normView).p2()), Point(dti.map(normOrtho).p2())
      self._pixelVectorCache[1] = pv
      self._pixelVectorCache[0] = key
      self._pixelVectorGlobalCache[key] = pv
      return self._pixelVectorCache[1]
  
imports: import operator
  import weakref
  from collections import OrderedDict
  from functools import reduce
  from math import hypot
  from typing import Optional
  from xml.etree.ElementTree import Element
  from ..None import functions
  from ..GraphicsScene import GraphicsScene
  from ..Point import Point
  from ..Qt import QtCore, QtWidgets, isQObjectAlive
label_desc: Use image node_id 10 for calling the GraphicsItem obj's underlying member method code with example usage: obj.pixelVectors(direction) and returns: self, None,  None, tuple, tuple, None,  None