Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Optimization API #241

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ Services
- Manage editable collections of GeoJSON features
- Persistent storage for custom geographic data

- **Optimization V1** `examples <./docs/optimization.md#optimization>`__, `website <https://www.mapbox.com/api-documentation/?language=Python#optimization>`__

- Retrieve a duration-optimized route

- **Tilequery V4** `examples <./docs/tilequery.md#tilequery>`__, `website <https://www.mapbox.com/api-documentation/?language=Python#tilequery>`__

- Retrieve data about specific features from a vector tileset
Expand Down
5 changes: 5 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Services
- Manage editable collections of GeoJSON features
- Persistent storage for custom geographic data

- **Optimization V1** `examples <./optimization.html#optimization>`__, `website <https://www.mapbox.com/api-documentation/?language=Python#optimization>`__

- Retrieve a duration-optimized route

- **Tilequery V4** `examples <./tilequery.html#tilequery>`__, `website <https://www.mapbox.com/api-documentation/?language=Python#tilequery>`__

- Retrieve data about specific features from a vector tileset
Expand Down Expand Up @@ -115,6 +119,7 @@ Documentation
analytics.md
mapmatching.md
static_style.md
optimization.md
tilequery.md
maps.md
api/mapbox.rst
Expand Down
77 changes: 77 additions & 0 deletions docs/optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Optimization

The `Optimization` class provides access to the Mapbox Optimization API. You can import it from either the `mapbox` module or the `mapbox.services.optimization` module.

__mapbox__:

```python
>>> from mapbox import Optimization

```

__mapbox.services.optimization__:

```python
>>> from mapbox.services.optimization import Optimization

```

See https://www.mapbox.com/api-documentation/#optimization for general documentation of the API.

Use of the Optimization API requires an access token, which you should set in your environment. For more information, see the [access tokens](access_tokens.md) documentation.

## Optimization Method

The public method of the `Optimization` class provides access to the Optimization API and returns an instance of [`requests.Response`](http://docs.python-requests.org/en/latest/api/#requests.Response).


## Usage: Retrieving Optimizations

Instantiate `Optimization`.

```python
>>> optimization = Optimization()

```

Call the `route` method, passing in values for `features` and `profile`. Pass in values for optional arguments as necessary - `geometries`, `overview`, `steps`, `waypoint_snapping`, `roundtrip`, `source`, `destination`, `distributions`, `annotations`, and `language`.

```python
>>> features = [
... {
... "type": "Feature",
... "properties": {},
... "geometry":
... {
... "type": "Point",
... "coordinates":
... [
... 0.0,
... 0.0
... ]
... }
... },
... {
... "type": "Feature",
... "properties": {},
... "geometry":
... {
... "type": "Point",
... "coordinates":
... [
... 1.0,
... 1.0
... ]
... }
... }
...]
>>> results = optimization.route(features, profile="mapbox/driving")

```

Evaluate whether the request succeeded, and retrieve the optimization object from the response object.

```python
>>> if results.status_code == 200:
... optimization_object = response.json()
```
3 changes: 2 additions & 1 deletion mapbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
from .services.static_style import StaticStyle
from .services.uploads import Uploader
from .services.analytics import Analytics
from .services.optimization import Optimization
from .services.tilequery import Tilequery
from .services.maps import Maps
from .services.maps import Maps
82 changes: 81 additions & 1 deletion mapbox/encoding.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import json

from .errors import InvalidFeatureError
from numbers import Number

from .compat import string_type

from .errors import (
InvalidFeatureError,
InvalidParameterError
)

import polyline


Expand Down Expand Up @@ -95,3 +103,75 @@ def encode_coordinates_json(features):
coords = {
'coordinates': list(read_points(features))}
return json.dumps(coords)


def validate_snapping(snaps, features):
bearings = []
radii = []
if snaps is None:
return (None, None)
if len(snaps) != len(features):
raise InvalidParameterError(
'Must provide exactly one snapping element for each input feature')
for snap in snaps:
if snap is None:
bearings.append(None)
radii.append(None)
else:
try:
# radius-only
radius = validate_radius(snap)
bearing = None
except InvalidParameterError:
# (radius, angle, range) tuple
try:
radius, angle, rng = snap
except ValueError:
raise InvalidParameterError(
'waypoint snapping should contain 3 elements: '
'(bearing, angle, range)')
validate_radius(radius)

try:
assert angle >= 0
assert angle <= 360
assert rng >= 0
assert rng <= 360
except (TypeError, AssertionError):
raise InvalidParameterError(
'angle and range must be between 0 and 360')
bearing = (angle, rng)

bearings.append(bearing)
radii.append(radius)

if all([b is None for b in bearings]):
bearings = None

return (bearings, radii)


def validate_radius(radius):
if radius is None:
return None

if isinstance(radius, string_type):
if radius != 'unlimited':
raise InvalidParameterError(
'{0} is not a valid radius'.format(radius))
elif isinstance(radius, Number):
if radius <= 0:
raise InvalidParameterError(
'radius must be greater than zero'.format(radius))
else:
raise InvalidParameterError(
'{0} is not a valid radius'.format(radius))

return radius


def encode_bearing(b):
if b is None:
return ''
else:
return '{},{}'.format(*b)
Loading