Skip to main content

A Python library for the Routable AI API

Project description

Python package Maintainability

pyrai: A Python library for the Routable AI API

Introduction

Pyrai makes it easy to use the Routable AI API to create, run, and visualize simulations with just 10 lines of code.

import pyrai
import datetime
rai = pyrai.Pyrai(api_key="API-KEY-HERE")
fleet = rai.create_live_fleet()
fleet.make_vehicle_online(vid=1, location=pyrai.Location(lat=42.36, lng=71.05), capacity=4)
fleet.add_request(rid=1, pickup=pyrai.Location(42.1,71.2), dropoff=pyrai.Location(42.3,71.4), load=4)
fleet.get_assignments()
fleet.forward_simulate("10m")
fleet.visualize()

Features

Pyrai allows you to create, run, and visualize simulations with the Routable AI API, right in Python.

Getting Started

Begin by importing the package and adding your API key.

import pyrai
API_KEY = "your-api-key-here"

Once you have added your API key, you can create a fleet:

rai = pyrai.Pyrai(api_key=API_KEY)
fleet = rai.create_sim_fleet()

You can also create a fleet directly from its API key and fleet key:

directly_created_fleet = pyrai.Fleet(api_key="api-key-here", fleet_key="fleet-key-here")

Vehicles

Once you have a fleet, you can add, update, and remove vehicles from it:

fleet.make_vehicle_online(vid=1, location=Location(50, 7), capacity=4)
veh = fleet.get_vehicle_info(1)

Vehicles adding, updating, and removing can be done either from the fleet or the individual vehicles:

# These lines do the same thing
veh.update(event=VehicleEvent.UNASSIGNED, location=Location(50,6), direction=0)
fleet.update_vehicle(vid=1, location=Location(50, 6), direction=0, event=VehicleEvent.UNASSIGNED)
>>> {'fleet': {'api_key': 'your-api-key-here', 'fleet_key': '6b515268-6125-43b4-bd34-2ecdb112e9aa'}, 'veh_id': 1, 'location': {'lat': 50.748227, 'lng': 5.992767}, 'assigned': False, 'req_ids': [], 'events': []}

Vehicles are easy to take offline and/or remove:

veh.make_offline()
veh.remove()

Requests

Requests can be added, queried, and cancelled similar to vehicles.

fleet.add_request(rid=1,
                  pickup=Location(30,40),
                  dropoff=Location(40,50),
                  load=4)
req=fleet.get_request(1)
req.cancel()
# Could also use fleet.cancel_request(rid=1)

Assignments

Once you have a fleet with requests and vehicles, you can use the API to assign vehicles to requests.

import random
fleet = rai.create_live_fleet()
import random
for v in range(20): # Add 20 random vehicles
  fleet.make_vehicle_online(v, 
      Location(50+random.gauss(0,1), 6+random.gauss(0,1)),
      4)
for r in range(100): # Add 100 random requests
  fleet.add_request(rid=r,
                  pickup = Location(50+random.gauss(0,5), 6+random.gauss(0,5)),
                  dropoff = Location(50+random.gauss(0,5), 6+random.gauss(0,5)),
                  load = 4)
fleet.get_assignments() # Get assignments
>>> {'vehs': [{'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'veh_id': 1, 'location': {'lat': 50.754699, 'lng': 5.681816}, 'assigned': True, 'req_ids': [80], 'events': [{'req_id': 80, 'location': {'lat': 50.754699, 'lng': 5.681816}, 'time': '2020-07-03T12:27:27Z', 'event': 'pickup'}, {'req_id': 80, 'location': {'lat': 51.541428, 'lng': 3.438608}, 'time': '2020-07-03T17:44:31Z', 'event': 'dropoff'}]}, {'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'veh_id': 17, 'location': {'lat': 50.751542, 'lng': 6.019059}, 'assigned': True, 'req_ids': [13], 'events': [{'req_id': 13, 'location': {'lat': 50.751542, 'lng': 6.019059}, 'time': '2020-07-03T12:27:27Z', 'event': 'pickup'}, {'req_id': 13, 'location': {'lat': 51.239186, 'lng': 3.42657}, 'time': '2020-07-03T18:33:33Z', 'event': 'dropoff'}]},..., {'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'veh_id': 3, 'location': {'lat': 50.753503, 'lng': 6.021277}, 'assigned': True, 'req_ids': [94], 'events': [{'req_id': 94, 'location': {'lat': 50.753503, 'lng': 6.021277}, 'time': '2020-07-03T12:27:27Z', 'event': 'pickup'}, {'req_id': 94, 'location': {'lat': 53.258865, 'lng': 7.267049}, 'time': '2020-07-03T20:12:17Z', 'event': 'dropoff'}]}], 'requests': [{'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'pickup': {'lat': 50.867703, 'lng': 6.091752}, 'dropoff': {'lat': 53.401362, 'lng': 5.25105}, 'request_time': '2020-07-03T12:26:47Z', 'req_id': 0, 'veh_id': 11, 'load': 4, 'assigned': True}, {'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'pickup': {'lat': 50.751542, 'lng': 6.019059}, 'dropoff': {'lat': 51.956534, 'lng': 6.823075}, 'request_time': '2020-07-03T12:26:47Z', 'req_id': 1, 'veh_id': -1, 'load': 4, 'assigned': False},..., {'fleet': {'api_key': 'your-api-key-here', 'fleet_key': 'your-fleet-key-here'}, 'pickup': {'lat': 51.302285, 'lng': 3.328629}, 'dropoff': {'lat': 50.748227, 'lng': 5.992767}, 'request_time': '2020-07-03T12:26:47Z', 'req_id': 99, 'veh_id': -1, 'load': 4, 'assigned': False}], 'notifications': []}

Forward Simulation

Once you have assignments, you can forward simulate for a specified duration

fleet.forward_simulate(duration="5m")

This updates the state of your vehicles and requests.

Visualization

Once you have a fleet that has accumulated events and run through a forward simulation, you can visualize the vehicles and requests:

fleet = pyrai.Fleet(api_key = "907fab5b-c35e-497f-988f-92fbb8835977", 
              fleet_key = "8af41885-d9bf-465d-9746-e54d8147646d")
fleet.visualize('2020-05-06T21:55:00Z',
                '2020-05-06T22:55:00Z')
<iframe
    width="100%"
    height="600"
    src="https://dashboard.routable.ai/pyraimap?start=2020-05-06T21:55:00Z&end=2020-05-06T22:55:00Z&api_key=907fab5b-c35e-497f-988f-92fbb8835977&fleet_key=8af41885-d9bf-465d-9746-e54d8147646d"
    frameborder="0"
    allowfullscreen
></iframe>

You can also plot various time series metrics:

fleet.plot_metrics([Metrics.PASSENGERS, Metrics.TOTAL_REQUESTS, Metrics.AVG_OCCUPANCY, Metrics.IDLE_VEHICLES], 
                  '2020-05-06T21:55:00Z',
                  '2020-05-06T22:55:00Z')
<html>
<head><meta charset="utf-8" /></head>
<body>
    <div>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax) {MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>
                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>    
            <div id="180a83a1-5c9a-4e58-b599-70b25490c5ae" class="plotly-graph-div" style="height:525px; width:100%;"></div>
            <script type="text/javascript">

                    window.PLOTLYENV=window.PLOTLYENV || {};

                if (document.getElementById("180a83a1-5c9a-4e58-b599-70b25490c5ae")) {
                    Plotly.newPlot(
                        '180a83a1-5c9a-4e58-b599-70b25490c5ae',
                        [{"mode": "lines+markers", "name": "passengers", "type": "scatter", "x": ["2020-05-06T21:55:00Z", "2020-05-06T22:00:00Z", "2020-05-06T22:05:00Z", "2020-05-06T22:10:00Z", "2020-05-06T22:15:00Z", "2020-05-06T22:20:00Z", "2020-05-06T22:25:00Z", "2020-05-06T22:30:00Z", "2020-05-06T22:35:00Z", "2020-05-06T22:40:00Z", "2020-05-06T22:45:00Z", "2020-05-06T22:50:00Z"], "y": [2, 5, 7, 12, 20, 17, 16, 16, 13, 13, 17, 14]}, {"mode": "lines+markers", "name": "total_requests", "type": "scatter", "x": ["2020-05-06T21:55:00Z", "2020-05-06T22:00:00Z", "2020-05-06T22:05:00Z", "2020-05-06T22:10:00Z", "2020-05-06T22:15:00Z", "2020-05-06T22:20:00Z", "2020-05-06T22:25:00Z", "2020-05-06T22:30:00Z", "2020-05-06T22:35:00Z", "2020-05-06T22:40:00Z", "2020-05-06T22:45:00Z", "2020-05-06T22:50:00Z"], "y": [8, 16, 22, 36, 43, 48, 59, 65, 77, 91, 98, 112]}, {"mode": "lines+markers", "name": "avg_occupancy", "type": "scatter", "x": ["2020-05-06T21:55:00Z", "2020-05-06T22:00:00Z", "2020-05-06T22:05:00Z", "2020-05-06T22:10:00Z", "2020-05-06T22:15:00Z", "2020-05-06T22:20:00Z", "2020-05-06T22:25:00Z", "2020-05-06T22:30:00Z", "2020-05-06T22:35:00Z", "2020-05-06T22:40:00Z", "2020-05-06T22:45:00Z", "2020-05-06T22:50:00Z"], "y": [0.25, 1.625, 1.85, 2.078333333333334, 4.166666666666667, 4.466666666666667, 4.05, 4.033333333333334, 2.9333333333333327, 2.9166666666666665, 4.000000000000001, 4.133333333333333]}, {"mode": "lines+markers", "name": "idle_vehicles", "type": "scatter", "x": ["2020-05-06T21:55:00Z", "2020-05-06T22:00:00Z", "2020-05-06T22:05:00Z", "2020-05-06T22:10:00Z", "2020-05-06T22:15:00Z", "2020-05-06T22:20:00Z", "2020-05-06T22:25:00Z", "2020-05-06T22:30:00Z", "2020-05-06T22:35:00Z", "2020-05-06T22:40:00Z", "2020-05-06T22:45:00Z", "2020-05-06T22:50:00Z"], "y": [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}],
                        {"template": {"data": {"bar": [{"error_x": {"color": "#2a3f5f"}, "error_y": {"color": "#2a3f5f"}, "marker": {"line": {"color": "#E5ECF6", "width": 0.5}}, "type": "bar"}], "barpolar": [{"marker": {"line": {"color": "#E5ECF6", "width": 0.5}}, "type": "barpolar"}], "carpet": [{"aaxis": {"endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f"}, "baxis": {"endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f"}, "type": "carpet"}], "choropleth": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "choropleth"}], "contour": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "contour"}], "contourcarpet": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "contourcarpet"}], "heatmap": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "heatmap"}], "heatmapgl": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "heatmapgl"}], "histogram": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "histogram"}], "histogram2d": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "histogram2d"}], "histogram2dcontour": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "histogram2dcontour"}], "mesh3d": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "mesh3d"}], "parcoords": [{"line": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "parcoords"}], "pie": [{"automargin": true, "type": "pie"}], "scatter": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatter"}], "scatter3d": [{"line": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatter3d"}], "scattercarpet": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattercarpet"}], "scattergeo": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattergeo"}], "scattergl": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattergl"}], "scattermapbox": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattermapbox"}], "scatterpolar": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterpolar"}], "scatterpolargl": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterpolargl"}], "scatterternary": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterternary"}], "surface": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "surface"}], "table": [{"cells": {"fill": {"color": "#EBF0F8"}, "line": {"color": "white"}}, "header": {"fill": {"color": "#C8D4E3"}, "line": {"color": "white"}}, "type": "table"}]}, "layout": {"annotationdefaults": {"arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1}, "coloraxis": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "colorscale": {"diverging": [[0, "#8e0152"], [0.1, "#c51b7d"], [0.2, "#de77ae"], [0.3, "#f1b6da"], [0.4, "#fde0ef"], [0.5, "#f7f7f7"], [0.6, "#e6f5d0"], [0.7, "#b8e186"], [0.8, "#7fbc41"], [0.9, "#4d9221"], [1, "#276419"]], "sequential": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "sequentialminus": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]]}, "colorway": ["#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52"], "font": {"color": "#2a3f5f"}, "geo": {"bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white"}, "hoverlabel": {"align": "left"}, "hovermode": "closest", "mapbox": {"style": "light"}, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": {"angularaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "bgcolor": "#E5ECF6", "radialaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}}, "scene": {"xaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}, "yaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}, "zaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}}, "shapedefaults": {"line": {"color": "#2a3f5f"}}, "ternary": {"aaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "baxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "bgcolor": "#E5ECF6", "caxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}}, "title": {"x": 0.05}, "xaxis": {"automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": {"standoff": 15}, "zerolinecolor": "white", "zerolinewidth": 2}, "yaxis": {"automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": {"standoff": 15}, "zerolinecolor": "white", "zerolinewidth": 2}}}},
                        {"responsive": true}
                    ).then(function(){

var gd = document.getElementById('180a83a1-5c9a-4e58-b599-70b25490c5ae');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })
                };

            </script>
        </div>
</body>
</html>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyrai-0.0.3.tar.gz (19.4 kB view details)

Uploaded Source

Built Distribution

pyrai-0.0.3-py3-none-any.whl (15.6 kB view details)

Uploaded Python 3

File details

Details for the file pyrai-0.0.3.tar.gz.

File metadata

  • Download URL: pyrai-0.0.3.tar.gz
  • Upload date:
  • Size: 19.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.47.0 CPython/3.8.3

File hashes

Hashes for pyrai-0.0.3.tar.gz
Algorithm Hash digest
SHA256 a7c46ee6c249b8dd95d548aaaa56502e0580a8596d276506c8aece4e46b4062b
MD5 ddb59fa3113ebeacf2990bd216236a4b
BLAKE2b-256 0e50560c8b66d3da7d167a58474bd35c993203999fd041f1efad2ea4b9ed7bee

See more details on using hashes here.

File details

Details for the file pyrai-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: pyrai-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 15.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.47.0 CPython/3.8.3

File hashes

Hashes for pyrai-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 2d51a4006b85a5e8113d892ccf1d08306eb7bd23cb20f679ed5ceacfd7edba01
MD5 bae4563f8a24e4831b2f1e5cf39be878
BLAKE2b-256 f716f062c4a112b01f625f400fc4959b4cb538de78383a2ff3e97852066dfa02

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page