{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quadtrees iterating on pairs of neighbouring items" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A quadtree is a tree data structure in which each node has exactly four children. It is a particularly efficient way to store elements when you need to quickly find them according to their x-y coordinates.\n", "\n", "A common problem with elements in quadtrees is to detect pairs of elements which are closer than a definite threshold.\n", "\n", "The proposed implementation efficiently addresses this problem." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from smartquadtree import Quadtree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creation & insertion of elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you instantiate your quadtree, you must specify the center of your space then the height and width." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "q = Quadtree(0, 0, 10, 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The output of a quadtree on the console is pretty explicit. (You can refer to next section for the meaning of \"No mask set\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "\n", "Total number of elements: 0\n", "No mask set" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can easily insert elements from which you can naturally infer x-y coordinates (e.g. tuples or lists)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "\n", "Total number of elements: 2\n", "No mask set\n", "First elements:\n", " (1, 2),\n", " (-3, 4),\n", " " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.insert((1, 2))\n", "q.insert((-3, 4))\n", "q" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "No error is raised if the element you are trying to insert is outside the scope of the quadtree. But it won't be stored anyway!" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "\n", "Total number of elements: 2\n", "No mask set\n", "First elements:\n", " (1, 2),\n", " (-3, 4),\n", " " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.insert((-20, 0))\n", "q" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to insert other Python objects, be sure to provide `get_x()` and `get_y()` methods to your class!" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class Point(object):\n", "\n", " def __init__(self, x, y, color):\n", " self.x = x\n", " self.y = y\n", " self.color = color\n", "\n", " def __repr__(self):\n", " return \"(%.2f, %.2f) %s\" % (self.x, self.y, self.color)\n", "\n", " def get_x(self):\n", " return self.x\n", "\n", " def get_y(self):\n", " return self.y\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You cannot insert elements of a different type from the first element inserted." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [], "source": [ "q.insert(Point(2, -7, \"red\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But feel free to create a new one and play with it:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "\n", "Total number of elements: 1\n", "No mask set\n", "First elements:\n", " (2.00, 7.00) red,\n", " " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "point_quadtree = Quadtree(5, 5, 5, 5)\n", "point_quadtree.insert(Point(2, 7, \"red\"))\n", "point_quadtree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple iteration" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from random import random\n", "q = Quadtree(0, 0, 10, 10, 16)\n", "for a in range(50):\n", " q.insert([random()*20-10, random()*20-10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `print` function does not display all elements and uses the `__repr__()` method of each element." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Total number of elements: 50\n", "No mask set\n", "First elements:\n", " [5.576253335483335, 2.9926458306078647],\n", " [2.956289387002718, 3.792134207741281],\n", " [3.9903269308895766, 5.492168007874362],\n", " ...\n" ] } ], "source": [ "print(q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can write our own iterator and print each element we encounter the way we like." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[5.58, 2.99] [2.96, 3.79] [3.99, 5.49] [3.43, 1.10] [7.73, 4.09] [9.67, 6.81] [2.95, 4.12] [0.14, 5.80] [2.77, 7.87] [0.05, 1.61] [-8.74, 7.64] [-1.22, 1.90] [-0.95, 3.91] [-3.17, 1.09] [-7.41, 4.26] [-8.25, 6.47] [-6.91, 3.80] [-3.73, 3.10] [-5.74, 8.80] [8.50, -9.31] [2.49, -9.10] [6.64, -8.61] [0.40, -2.93] [7.99, -4.08] [4.71, -6.75] [0.12, -1.84] [0.72, -2.94] [9.62, -9.90] [0.15, -9.75] [8.67, -7.19] [2.44, -3.60] [5.08, -8.63] [8.86, -1.87] [1.07, -9.43] [-7.96, -5.53] [-2.53, -5.75] [-1.31, -5.81] [-7.24, -3.55] [-8.76, -9.37] [-8.48, -1.33] [-1.28, -0.69] [-6.60, -4.65] [-4.28, -0.89] [-7.56, -7.31] [-4.72, -7.02] [-1.98, -2.33] [-3.43, -5.74] [-3.71, -1.13] [-1.01, -7.29] [-2.04, -5.90] " ] } ], "source": [ "from __future__ import print_function\n", "for p in q.elements():\n", " print (\"[%.2f, %.2f]\" % (p[0], p[1]), end=\" \")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is easy to filter the iteration process and apply the function only on elements inside a given polygon. Use the `set_mask()` method and pass a list of x-y coordinates. The polygon will be automatically closed." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Total number of elements: 50\n", "Total number of elements inside mask: 15\n", "First elements inside the mask:\n", " [2.956289387002718, 3.792134207741281],\n", " [2.945472950394006, 4.1166899654293765],\n", " [0.14379102547949074, 5.797490949080599],\n", " ...\n" ] } ], "source": [ "q.set_mask([(-3, -7), (-3, 7), (3, 7), (3, -7)])\n", "print(q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same approach can be used to count the number of elements inside the quadtree." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15\n", "50\n" ] } ], "source": [ "print (sum (1 for x in q.elements()))\n", "print (sum (1 for x in q.elements(ignore_mask=True)))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a mask is set on the quadtree, we only counted the elements inside the mask. You can use the `size()` method to count elements and ignore the mask by default. Disabling the mask with `set_mask(None)` is also a possibility." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "50 elements (size method)\n", "15 elements (don't ignore the mask)\n", "50 elements (disable the mask)\n" ] } ], "source": [ "print (\"%d elements (size method)\" % q.size())\n", "print (\"%d elements (don't ignore the mask)\" % q.size(False))\n", "\n", "q.set_mask(None)\n", "print (\"%d elements (disable the mask)\" % q.size())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Playing with plots" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "from matplotlib import pyplot as plt\n", " \n", "q = Quadtree(5, 5, 5, 5, 10)\n", "\n", "for a in range(200):\n", " q.insert([random()*10, random()*10])\n", " \n", "fig = plt.figure()\n", "plt.axis([0, 10, 0, 10])\n", "\n", "q.set_mask(None)\n", "for p in q.elements():\n", " plt.plot([p[0]], [p[1]], 'o', color='lightgrey')\n", "\n", "q.set_mask([(3, 3), (3, 7), (7, 7), (7, 3)])\n", "\n", "for p in q.elements():\n", " plt.plot([p[0]], [p[1]], 'ro')\n", "\n", "_ = plt.plot([3, 3, 7, 7, 3], [3, 7, 7, 3, 3], 'r')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Iteration on pairs of neighbouring elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Iterating on pairs of neighbouring elements is possible through the `neighbour_elements()` function. It works as a generator and yields pair of elements, the first one being inside the mask (if specified), the second one being in the same cell or in any neighbouring cell, also in the mask.\n", "\n", "Note that if `(a, b)` is yielded by `neighbour_elements()`, `(b, a)` will be omitted from future yields." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "q = Quadtree(5, 5, 5, 5, 10)\n", "q.set_limitation(2) # do not create a new subdivision if one side of the cell is below 2\n", "\n", "for a in range(200):\n", " q.insert([random()*10, random()*10])\n", "\n", "fig = plt.figure()\n", "plt.axis([0, 10, 0, 10])\n", "\n", "for p in q.elements():\n", " plt.plot([p[0]], [p[1]], 'o', color='lightgrey')\n", "\n", "q.set_mask([(1, 1), (4, 1), (5, 4), (2, 5), (1, 1)])\n", " \n", "for p in q.elements():\n", " plt.plot([p[0]], [p[1]], 'o', color='green')\n", " \n", "for p1, p2 in q.neighbour_elements():\n", " if ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 < 1):\n", " plt.plot([p1[0]], [p1[1]], 'o', color='red')\n", " plt.plot([p2[0]], [p2[1]], 'o', color='red')\n", " plt.plot([p1[0], p2[0]], [p1[1], p2[1]], 'red')\n", "\n", "_ = plt.plot([1, 4, 5, 2, 1], [1, 1, 4, 5, 1], 'r')\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.3" } }, "nbformat": 4, "nbformat_minor": 0 }