{
  "__type": "IngestedDoc",
  "__tag": 4010,
  "_content": {},
  "_ordered_sections": [],
  "item_file": null,
  "item_line": null,
  "item_type": null,
  "aliases": [],
  "example_section_data": {
    "__type": "Section",
    "__tag": 4015,
    "children": [],
    "title": [],
    "level": 0,
    "target": null
  },
  "see_also": [],
  "signature": null,
  "references": null,
  "qa": "tutorial:spatial",
  "arbitrary": [
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " can compute triangulations, Voronoi diagrams, and convex hulls of a set of points, by leveraging the "
            },
            {
              "__type": "Link",
              "__tag": 4049,
              "children": [
                {
                  "__type": "Text",
                  "__tag": 4046,
                  "value": "Qhull"
                }
              ],
              "url": "http://qhull.org/",
              "title": ""
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " library."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Moreover, it contains "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "KDTree",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " implementations for nearest-neighbor point queries, and utilities for distance computations in various metrics."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Spatial Data Structures and Algorithms ("
        },
        {
          "__type": "InlineRole",
          "__tag": 4003,
          "value": "scipy.spatial",
          "domain": null,
          "role": null,
          "inventory": null
        },
        {
          "__type": "Text",
          "__tag": 4046,
          "value": ")"
        }
      ],
      "level": 0,
      "target": "qhulltutorial"
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The Delaunay triangulation is a subdivision of a set of points into a non-overlapping set of triangles, such that no point is inside the circumcircle of any triangle. In practice, such triangulations tend to avoid triangles with small angles."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Delaunay triangulation can be computed using "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " as follows:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> from scipy.spatial import Delaunay\n>>> import numpy as np\n>>> points = np.array([[0, 0], [0, 1.1], [1, 0], [1, 1]])\n>>> tri = Delaunay(points)\n\nWe can visualize it:\n\n>>> import matplotlib.pyplot as plt\n>>> plt.triplot(points[:,0], points[:,1], tri.simplices)\n>>> plt.plot(points[:,0], points[:,1], 'o')\n\nAnd add some further decorations:\n\n>>> for j, p in enumerate(points):\n...     plt.text(p[0]-0.03, p[1]+0.03, j, ha='right') # label the points\n>>> for j, s in enumerate(tri.simplices):\n...     p = points[s].mean(axis=0)\n...     plt.text(p[0], p[1], '#%d' % j, ha='center') # label triangles\n>>> plt.xlim(-0.5, 1.5); plt.ylim(-0.5, 1.5)\n>>> plt.show()",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The structure of the triangulation is encoded in the following way: the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "simplices"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " attribute contains the indices of the points in the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "points"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " array that make up the triangle. For instance:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> i = 1\n>>> tri.simplices[i,:]\narray([3, 1, 0], dtype=int32)\n>>> points[tri.simplices[i,:]]\narray([[ 1. ,  1. ],\n       [ 0. ,  1.1],\n       [ 0. ,  0. ]])",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Moreover, neighboring triangles can also be found:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> tri.neighbors[i]\narray([-1,  0, -1], dtype=int32)",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "What this tells us is that this triangle has triangle #0 as a neighbor, but no other neighbors. Moreover, it tells us that neighbor 0 is opposite the vertex 1 of the triangle:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> points[tri.simplices[i, 1]]\narray([ 0. ,  1.1])",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Indeed, from the figure, we see that this is the case."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Qhull can also perform tessellations to simplices for higher-dimensional point sets (for instance, subdivision into tetrahedra in 3-D)."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Delaunay triangulations"
        }
      ],
      "level": 1,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "It is important to note that not "
            },
            {
              "__type": "Emphasis",
              "__tag": 4047,
              "children": [
                {
                  "__type": "Text",
                  "__tag": 4046,
                  "value": "all"
                }
              ]
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " points necessarily appear as vertices of the triangulation, due to numerical precision issues in forming the triangulation. Consider the above with a duplicated point:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> points = np.array([[0, 0], [0, 1], [1, 0], [1, 1], [1, 1]])\n>>> tri = Delaunay(points)\n>>> np.unique(tri.simplices.ravel())\narray([0, 1, 2, 3], dtype=int32)",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Observe that point #4, which is a duplicate, does not occur as a vertex of the triangulation. That this happened is recorded:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> tri.coplanar\narray([[4, 0, 3]], dtype=int32)",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "This means that point 4 resides near triangle 0 and vertex 3, but is not included in the triangulation."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Note that such degeneracies can occur not only because of duplicated points, but also for more complicated geometrical reasons, even in point sets that at first sight seem well-behaved."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "However, Qhull has the \"QJ\" option, which instructs it to perturb the input data randomly until degeneracies are resolved:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> tri = Delaunay(points, qhull_options=\"QJ Pp\")\n>>> points[tri.simplices]\narray([[[1, 0],\n        [1, 1],\n        [0, 0]],\n       [[1, 1],\n        [1, 1],\n        [1, 0]],\n       [[1, 1],\n        [0, 1],\n        [0, 0]],\n       [[0, 1],\n        [1, 1],\n        [1, 1]]])",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Two new triangles appeared. However, we see that they are degenerate and have zero area."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Coplanar points"
        }
      ],
      "level": 2,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "A convex hull is the smallest convex object containing all points in a given point set."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "These can be computed via the Qhull wrappers in "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " as follows:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> from scipy.spatial import ConvexHull\n>>> rng = np.random.default_rng()\n>>> points = rng.random((30, 2))   # 30 random points in 2-D\n>>> hull = ConvexHull(points)\n\nThe convex hull is represented as a set of N 1-D simplices,\nwhich in 2-D means line segments. The storage scheme is exactly the\nsame as for the simplices in the Delaunay triangulation discussed\nabove.\n\nWe can illustrate the above result:\n\n>>> import matplotlib.pyplot as plt\n>>> plt.plot(points[:,0], points[:,1], 'o')\n>>> for simplex in hull.simplices:\n...     plt.plot(points[simplex,0], points[simplex,1], 'k-')\n>>> plt.show()",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The same can be achieved with "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial.convex_hull_plot_2d",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial._plotutils:convex_hull_plot_2d"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Convex hulls"
        }
      ],
      "level": 1,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "A Voronoi diagram is a subdivision of the space into the nearest neighborhoods of a given set of points."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "There are two ways to approach this object using "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ". First, one can use the "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "KDTree",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " to answer the question \"which of the points is closest to this one\", and define the regions that way:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> from scipy.spatial import KDTree\n>>> points = np.array([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2],\n...                    [2, 0], [2, 1], [2, 2]])\n>>> tree = KDTree(points)\n>>> tree.query([0.1, 0.1])\n(0.14142135623730953, 0)\n\nSo the point ``(0.1, 0.1)`` belongs to region ``0``. In color:\n\n>>> x = np.linspace(-0.5, 2.5, 31)\n>>> y = np.linspace(-0.5, 2.5, 33)\n>>> xx, yy = np.meshgrid(x, y)\n>>> xy = np.c_[xx.ravel(), yy.ravel()]\n>>> import matplotlib.pyplot as plt\n>>> dx_half, dy_half = np.diff(x[:2])[0] / 2., np.diff(y[:2])[0] / 2.\n>>> x_edges = np.concatenate((x - dx_half, [x[-1] + dx_half]))\n>>> y_edges = np.concatenate((y - dy_half, [y[-1] + dy_half]))\n>>> plt.pcolormesh(x_edges, y_edges, tree.query(xy)[1].reshape(33, 31), shading='flat')\n>>> plt.plot(points[:,0], points[:,1], 'ko')\n>>> plt.show()\n\nThis does not, however, give the Voronoi diagram as a geometrical\nobject.\n\nThe representation in terms of lines and points can be again\nobtained via the Qhull wrappers in `scipy.spatial`:\n\n>>> from scipy.spatial import Voronoi\n>>> vor = Voronoi(points)\n>>> vor.vertices\narray([[0.5, 0.5],\n       [0.5, 1.5],\n       [1.5, 0.5],\n       [1.5, 1.5]])\n\nThe Voronoi vertices denote the set of points forming the polygonal\nedges of the Voronoi regions. In this case, there are 9 different\nregions:\n\n>>> vor.regions\n[[], [-1, 0], [-1, 1], [1, -1, 0], [3, -1, 2], [-1, 3], [-1, 2], [0, 1, 3, 2], [2, -1, 0], [3, -1, 1]]\n\nNegative value ``-1`` again indicates a point at infinity. Indeed,\nonly one of the regions, ``[0, 1, 3, 2]``, is bounded. Note here that\ndue to similar numerical precision issues as in Delaunay triangulation\nabove, there may be fewer Voronoi regions than input points.\n\nThe ridges (lines in 2-D) separating the regions are described as a\nsimilar collection of simplices as the convex hull pieces:\n\n>>> vor.ridge_vertices\n[[-1, 0], [-1, 0], [-1, 1], [-1, 1], [0, 1], [-1, 3], [-1, 2], [2, 3], [-1, 3], [-1, 2], [1, 3], [0, 2]]\n\nThese numbers present the indices of the Voronoi vertices making up the\nline segments. ``-1`` is again a point at infinity --- only 4 of\nthe 12 lines are a bounded line segment, while others extend to\ninfinity.\n\nThe Voronoi ridges are perpendicular to the lines drawn between the\ninput points. To which two points each ridge corresponds is also\nrecorded:\n\n>>> vor.ridge_points\narray([[0, 3],\n       [0, 1],\n       [2, 5],\n       [2, 1],\n       [1, 4],\n       [7, 8],\n       [7, 6],\n       [7, 4],\n       [8, 5],\n       [6, 3],\n       [4, 5],\n       [4, 3]], dtype=int32)\n\nThis information, taken together, is enough to construct the full\ndiagram.\n\nWe can plot it as follows. First, the points and the Voronoi vertices:\n\n>>> plt.plot(points[:, 0], points[:, 1], 'o')\n>>> plt.plot(vor.vertices[:, 0], vor.vertices[:, 1], '*')\n>>> plt.xlim(-1, 3); plt.ylim(-1, 3)\n\nPlotting the finite line segments goes as for the convex hull,\nbut now we have to guard for the infinite edges:\n\n>>> for simplex in vor.ridge_vertices:\n...     simplex = np.asarray(simplex)\n...     if np.all(simplex >= 0):\n...         plt.plot(vor.vertices[simplex, 0], vor.vertices[simplex, 1], 'k-')\n\nThe ridges extending to infinity require a bit more care:\n\n>>> center = points.mean(axis=0)\n>>> for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):\n...     simplex = np.asarray(simplex)\n...     if np.any(simplex < 0):\n...         i = simplex[simplex >= 0][0] # finite end Voronoi vertex\n...         t = points[pointidx[1]] - points[pointidx[0]]  # tangent\n...         t = t / np.linalg.norm(t)\n...         n = np.array([-t[1], t[0]]) # normal\n...         midpoint = points[pointidx].mean(axis=0)\n...         far_point = vor.vertices[i] + np.sign(np.dot(midpoint - center, n)) * n * 100\n...         plt.plot([vor.vertices[i,0], far_point[0]],\n...                  [vor.vertices[i,1], far_point[1]], 'k--')\n>>> plt.show()",
          "execution_status": null
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "This plot can also be created using "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "scipy.spatial.voronoi_plot_2d",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "scipy",
                "version": "*",
                "kind": "api",
                "path": "scipy.spatial._plotutils:voronoi_plot_2d"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Voronoi diagrams can be used to create interesting generative art.  Try playing with the settings of this "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "mandala"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " function to create your own!"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": ">>> import numpy as np\n>>> from scipy import spatial\n>>> import matplotlib.pyplot as plt\n\n>>> def mandala(n_iter, n_points, radius):\n...     \"\"\"Creates a mandala figure using Voronoi tessellations.\n...\n...     Parameters\n...     ----------\n...     n_iter : int\n...         Number of iterations, i.e. how many times the equidistant points will\n...         be generated.\n...     n_points : int\n...         Number of points to draw per iteration.\n...     radius : scalar\n...         The radial expansion factor.\n...\n...     Returns\n...     -------\n...     fig : matplotlib.Figure instance\n...\n...     Notes\n...     -----\n...     This code is adapted from the work of Audrey Roy Greenfeld [1]_ and Carlos\n...     Focil-Espinosa [2]_, who created beautiful mandalas with Python code.  That\n...     code in turn was based on Antonio Sánchez Chinchón's R code [3]_.\n...\n...     References\n...     ----------\n...     .. [1] https://www.codemakesmehappy.com/2019/09/voronoi-mandalas.html\n...\n...     .. [2] https://github.com/CarlosFocil/mandalapy\n...\n...     .. [3] https://github.com/aschinchon/mandalas\n...\n...     \"\"\"\n...     fig = plt.figure(figsize=(10, 10))\n...     ax = fig.add_subplot(111)\n...     ax.set_axis_off()\n...     ax.set_aspect('equal', adjustable='box')\n...\n...     angles = np.linspace(0, 2*np.pi * (1 - 1/n_points), num=n_points) + np.pi/2\n...     # Starting from a single center point, add points iteratively\n...     xy = np.array([[0, 0]])\n...     for k in range(n_iter):\n...         t1 = np.array([])\n...         t2 = np.array([])\n...         # Add `n_points` new points around each existing point in this iteration\n...         for i in range(xy.shape[0]):\n...             t1 = np.append(t1, xy[i, 0] + radius**k * np.cos(angles))\n...             t2 = np.append(t2, xy[i, 1] + radius**k * np.sin(angles))\n...\n...         xy = np.column_stack((t1, t2))\n...\n...     # Create the Mandala figure via a Voronoi plot\n...     spatial.voronoi_plot_2d(spatial.Voronoi(xy), ax=ax)\n...\n...     return fig\n\n>>> # Modify the following parameters in order to get different figures\n>>> n_iter = 3\n>>> n_points = 6\n>>> radius = 4\n\n>>> fig = mandala(n_iter, n_points, radius)\n>>> plt.show()",
          "execution_status": null
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Voronoi diagrams"
        }
      ],
      "level": 1,
      "target": null
    }
  ],
  "local_refs": []
}