class_docstr: Given a :class:`~.Diagram` and the corresponding
  :class:`DiagramGrid`, produces the Xy-pic representation of the
  diagram.
  
  The most important method in this class is ``draw``.  Consider the
  following triangle diagram:
  
  >>> from sympy.categories import Object, NamedMorphism, Diagram
  >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer
  >>> A = Object("A")
  >>> B = Object("B")
  >>> C = Object("C")
  >>> f = NamedMorphism(A, B, "f")
  >>> g = NamedMorphism(B, C, "g")
  >>> diagram = Diagram([f, g], {g * f: "unique"})
  
  To draw this diagram, its objects need to be laid out with a
  :class:`DiagramGrid`::
  
  >>> grid = DiagramGrid(diagram)
  
  Finally, the drawing:
  
  >>> drawer = XypicDiagramDrawer()
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
  C &
  }
  
  For further details see the docstring of this method.
  
  To control the appearance of the arrows, formatters are used.  The
  dictionary ``arrow_formatters`` maps morphisms to formatter
  functions.  A formatter is accepts an
  :class:`ArrowStringDescription` and is allowed to modify any of
  the arrow properties exposed thereby.  For example, to have all
  morphisms with the property ``unique`` appear as dashed arrows,
  and to have their names prepended with `\exists !`, the following
  should be done:
  
  >>> def formatter(astr):
  ...   astr.label = r"\exists !" + astr.label
  ...   astr.arrow_style = "{-->}"
  >>> drawer.arrow_formatters["unique"] = formatter
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar@{-->}[d]_{\exists !g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
  C &
  }
  
  To modify the appearance of all arrows in the diagram, set
  ``default_arrow_formatter``.  For example, to place all morphism
  labels a little bit farther from the arrow head so that they look
  more centred, do as follows:
  
  >>> def default_formatter(astr):
  ...   astr.label_displacement = "(0.45)"
  >>> drawer.default_arrow_formatter = default_formatter
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar@{-->}[d]_(0.45){\exists !g\circ f} \ar[r]^(0.45){f} & B \ar[ld]^(0.45){g} \\
  C &
  }
  
  In some diagrams some morphisms are drawn as curved arrows.
  Consider the following diagram:
  
  >>> D = Object("D")
  >>> E = Object("E")
  >>> h = NamedMorphism(D, A, "h")
  >>> k = NamedMorphism(D, B, "k")
  >>> diagram = Diagram([f, g, h, k])
  >>> grid = DiagramGrid(diagram)
  >>> drawer = XypicDiagramDrawer()
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_3mm/[ll]_{h} \\
  & C &
  }
  
  To control how far the morphisms are curved by default, one can
  use the ``unit`` and ``default_curving_amount`` attributes:
  
  >>> drawer.unit = "cm"
  >>> drawer.default_curving_amount = 1
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_1cm/[ll]_{h} \\
  & C &
  }
  
  In some diagrams, there are multiple curved morphisms between the
  same two objects.  To control by how much the curving changes
  between two such successive morphisms, use
  ``default_curving_step``:
  
  >>> drawer.default_curving_step = 1
  >>> h1 = NamedMorphism(A, D, "h1")
  >>> diagram = Diagram([f, g, h, k, h1])
  >>> grid = DiagramGrid(diagram)
  >>> print(drawer.draw(diagram, grid))
  \xymatrix{
  A \ar[r]_{f} \ar@/^1cm/[rr]^{h_{1}} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_2cm/[ll]_{h} \\
  & C &
  }
  
  The default value of ``default_curving_step`` is 4 units.
  
  See Also
  ========
  
  draw, ArrowStringDescription
class_docstr_tok: ["Given","a",":","class",":","`","~.Diagram","`","and","the","corresponding",":","class",":","`","DiagramGrid","`",",","produces","the","Xy-pic","representation","of","the","diagram",".","The","most","important","method","in","this","class","is","``","draw","``",".","Consider","the","following","triangle","diagram",":",">",">",">","from","sympy.categories","import","Object",",","NamedMorphism",",","Diagram",">",">",">","from","sympy.categories","import","DiagramGrid",",","XypicDiagramDrawer",">",">",">","A","=","Object","(","``","A","''",")",">",">",">","B","=","Object","(","``","B","''",")",">",">",">","C","=","Object","(","``","C","''",")",">",">",">","f","=","NamedMorphism","(","A",",","B",",","``","f","''",")",">",">",">","g","=","NamedMorphism","(","B",",","C",",","``","g","''",")",">",">",">","diagram","=","Diagram","(","[","f",",","g","]",",","{","g","*","f",":","``","unique","''","}",")","To","draw","this","diagram",",","its","objects","need","to","be","laid","out","with","a",":","class",":","`","DiagramGrid","`",":",":",">",">",">","grid","=","DiagramGrid","(","diagram",")","Finally",",","the","drawing",":",">",">",">","drawer","=","XypicDiagramDrawer","(",")",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","[","d","]","_","{","g\\circ","f","}","\\ar","[","r","]","^","{","f","}","&","B","\\ar","[","ld","]","^","{","g","}","\\\\","C","&","}","For","further","details","see","the","docstring","of","this","method",".","To","control","the","appearance","of","the","arrows",",","formatters","are","used",".","The","dictionary","``","arrow_formatters","``","maps","morphisms","to","formatter","functions",".","A","formatter","is","accepts","an",":","class",":","`","ArrowStringDescription","`","and","is","allowed","to","modify","any","of","the","arrow","properties","exposed","thereby",".","For","example",",","to","have","all","morphisms","with","the","property","``","unique","``","appear","as","dashed","arrows",",","and","to","have","their","names","prepended","with","`","\\exists","!","`",",","the","following","should","be","done",":",">",">",">","def","formatter","(","astr",")",":","...","astr.label","=","r","''","\\exists","!","''","+","astr.label","...","astr.arrow_style","=","``","{","--",">","}","''",">",">",">","drawer.arrow_formatters","[","``","unique","''","]","=","formatter",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","@","{","--",">","}","[","d","]","_","{","\\exists","!","g\\circ","f","}","\\ar","[","r","]","^","{","f","}","&","B","\\ar","[","ld","]","^","{","g","}","\\\\","C","&","}","To","modify","the","appearance","of","all","arrows","in","the","diagram",",","set","``","default_arrow_formatter","``",".","For","example",",","to","place","all","morphism","labels","a","little","bit","farther","from","the","arrow","head","so","that","they","look","more","centred",",","do","as","follows",":",">",">",">","def","default_formatter","(","astr",")",":","...","astr.label_displacement","=","``","(","0.45",")","''",">",">",">","drawer.default_arrow_formatter","=","default_formatter",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","@","{","--",">","}","[","d","]","_","(","0.45",")","{","\\exists","!","g\\circ","f","}","\\ar","[","r","]","^","(","0.45",")","{","f","}","&","B","\\ar","[","ld","]","^","(","0.45",")","{","g","}","\\\\","C","&","}","In","some","diagrams","some","morphisms","are","drawn","as","curved","arrows",".","Consider","the","following","diagram",":",">",">",">","D","=","Object","(","``","D","''",")",">",">",">","E","=","Object","(","``","E","''",")",">",">",">","h","=","NamedMorphism","(","D",",","A",",","``","h","''",")",">",">",">","k","=","NamedMorphism","(","D",",","B",",","``","k","''",")",">",">",">","diagram","=","Diagram","(","[","f",",","g",",","h",",","k","]",")",">",">",">","grid","=","DiagramGrid","(","diagram",")",">",">",">","drawer","=","XypicDiagramDrawer","(",")",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","[","r","]","_","{","f","}","&","B","\\ar","[","d","]","^","{","g","}","&","D","\\ar","[","l","]","^","{","k","}","\\ar","@","\/_3mm\/","[","ll","]","_","{","h","}","\\\\","&","C","&","}","To","control","how","far","the","morphisms","are","curved","by","default",",","one","can","use","the","``","unit","``","and","``","default_curving_amount","``","attributes",":",">",">",">","drawer.unit","=","``","cm","''",">",">",">","drawer.default_curving_amount","=","1",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","[","r","]","_","{","f","}","&","B","\\ar","[","d","]","^","{","g","}","&","D","\\ar","[","l","]","^","{","k","}","\\ar","@","\/_1cm\/","[","ll","]","_","{","h","}","\\\\","&","C","&","}","In","some","diagrams",",","there","are","multiple","curved","morphisms","between","the","same","two","objects",".","To","control","by","how","much","the","curving","changes","between","two","such","successive","morphisms",",","use","``","default_curving_step","``",":",">",">",">","drawer.default_curving_step","=","1",">",">",">","h1","=","NamedMorphism","(","A",",","D",",","``","h1","''",")",">",">",">","diagram","=","Diagram","(","[","f",",","g",",","h",",","k",",","h1","]",")",">",">",">","grid","=","DiagramGrid","(","diagram",")",">",">",">","print","(","drawer.draw","(","diagram",",","grid",")",")","\\xymatrix","{","A","\\ar","[","r","]","_","{","f","}","\\ar","@","\/^1cm\/","[","rr","]","^","{","h_","{","1","}","}","&","B","\\ar","[","d","]","^","{","g","}","&","D","\\ar","[","l","]","^","{","k","}","\\ar","@","\/_2cm\/","[","ll","]","_","{","h","}","\\\\","&","C","&","}","The","default","value","of","``","default_curving_step","``","is","4","units",".","See","Also","========","draw",",","ArrowStringDescription"]
docstr: Provides a morphism sorting key such that horizontal or
  vertical morphisms between neighbouring objects come
  first, then horizontal or vertical morphisms between more
  far away objects, and finally, all other morphisms.
docstr_tok: ["Provides","a","morphism","sorting","key","such","that","horizontal","or","vertical","morphisms","between","neighbouring","objects","come","first",",","then","horizontal","or","vertical","morphisms","between","more","far","away","objects",",","and","finally",",","all","other","morphisms","."]
code: def _morphism_sort_key(morphism, object_coords):
      """
      Provides a morphism sorting key such that horizontal or
      vertical morphisms between neighbouring objects come
      first, then horizontal or vertical morphisms between more
      far away objects, and finally, all other morphisms.
      """
      (i, j) = object_coords[morphism.domain]
      (target_i, target_j) = object_coords[morphism.codomain]
  
      if morphism.domain == morphism.codomain:
          # Loop morphisms should get after diagonal morphisms
          # so that the proper direction in which to curve the
          # loop can be determined.
          return (3, 0, default_sort_key(morphism))
  
      if target_i == i:
          return (1, abs(target_j - j), default_sort_key(morphism))
  
      if target_j == j:
          return (1, abs(target_i - i), default_sort_key(morphism))
  
      # Diagonal morphism.
      return (2, 0, default_sort_key(morphism))
  
imports: from sympy.categories import CompositeMorphism, IdentityMorphism, NamedMorphism, Diagram
  from sympy.core import Dict, Symbol, default_sort_key
  from sympy.printing.latex import latex
  from sympy.sets import FiniteSet
  from sympy.utilities.iterables import iterable
  from sympy.utilities.decorator import doctest_depends_on
  from itertools import chain
label_desc: Use image node_id 10 for calling the XypicDiagramDrawer obj's underlying member method code with example usage: obj._morphism_sort_key(morphism, object_coords) and returns: int,  int,  default_sort_key, int,  int,  default_sort_key, int,  abs,  default_sort_key, int,  abs,  default_sort_key