{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n\n# Path computation\n\nIn this example, we show how to perform path computation for Coquimbo, a city in La Serena Metropolitan Area in Chile.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        ".. seealso::\n    Several functions, methods, classes and modules are used in this example:\n\n    * :func:`aequilibrae.paths.Graph`\n    * :func:`aequilibrae.paths.PathResults`\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Imports\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from uuid import uuid4\nfrom tempfile import gettempdir\nfrom os.path import join\nfrom aequilibrae.utils.create_example import create_example"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We create the example project inside our temp folder\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "fldr = join(gettempdir(), uuid4().hex)\n\nproject = create_example(fldr, \"coquimbo\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import logging\nimport sys"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We the project opens, we can tell the logger to direct all messages to the terminal as well\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "logger = project.logger\nstdout_handler = logging.StreamHandler(sys.stdout)\nformatter = logging.Formatter(\"%(asctime)s;%(levelname)s ; %(message)s\")\nstdout_handler.setFormatter(formatter)\nlogger.addHandler(stdout_handler)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Path Computation\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We build all graphs\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.network.build_graphs()\n# We get warnings that several fields in the project are filled with ``NaN``s. \n# This is true, but we won't use those fields."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We grab the graph for cars,\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "graph = project.network.graphs[\"c\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "we'll also see what graphs are available.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.network.graphs.keys()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's say we want to minimise the distance,\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "graph.set_graph(\"distance\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "and will skim time and distance while we are at it.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "graph.set_skimming([\"travel_time\", \"distance\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's create a path results object from the graph and compute a path from \nnode 32343 (near the airport) to 22041 (near Fort Lambert, overlooking Coquimbo Bay).\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = graph.compute_path(32343, 22041)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Computing paths directly from the graph is more straightforward, though we could\nalternatively use ``PathComputation`` class to achieve the same result.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# from aequilibrae.paths import PathResults\n\n# res = PathResults()\n# res.prepare(graph)\n# res.compute_path(32343, 22041)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can get the sequence of nodes we traverse\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.path_nodes"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can get the link sequence we traverse\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.path"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can get the mileposts for our sequence of nodes\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.milepost"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Additionally, you can also provide ``early_exit=True`` or ``a_star=True`` to `compute_path` to \nadjust its path-finding behavior.\n\nProviding ``early_exit=True`` allows you to quit the path-finding procedure once it discovers \nthe destination. This setup works better for topographically close origin-destination pairs. \nHowever, exiting early may cause subsequent calls to ``update_trace`` to recompute the tree \nin cases where it typically wouldn't.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = graph.compute_path(32343, 22041, early_exit=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you prefer to find a potentially non-optimal path to the destination faster, \nprovide ``a_star=True`` to use `A*` with a heuristic. This method always recomputes the \npath's nodes, links, skims, and mileposts with ``update_trace``. \nNote that a_star takes precedence over early_exit.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = graph.compute_path(32343, 22041, a_star=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you are using `a_star`, it is possible to use different heuristics to compute the path. \nBy default, an equirectangular heuristic is used, and we can view the available heuristics via:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.get_heuristics()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you prefer a more accurate but slower heuristic, you can choose \"haversine\", by setting:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = graph.compute_path(32343, 22041, a_star=True, heuristic=\"haversine\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Suppose you want to adjust the path to the University of La Serena instead of Fort Lambert. \nIt is possible to adjust the existing path computation for this alteration. The following code \nallows both `early_exit` and `A*` settings to persist when calling ``update_trace``. If you\u2019d \nlike to adjust them for subsequent path re-computations set the ``res.early_exit`` and \n``res.a_star`` attributes. Notice that this procedure is much faster when you have large networks.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.a_star = False\nres.update_trace(73131)\n\nres.path_nodes"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you want to show the path in Python.\n\nWe do NOT recommend this, though... It is very slow for real networks.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "links = project.network.links.data.set_index(\"link_id\")\nlinks = links.loc[res.path]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "links.explore(color=\"blue\", style_kwds={'weight':5})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.close()"
      ]
    }
  ],
  "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.10.18"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}