Пример #1
0
def staticmap(ctx, mapid, output, features, lat, lon, zoom, size):
    """
    Generate static map images from existing Mapbox map ids.
    Optionally overlay with geojson features.

      $ mapbox staticmap --features features.geojson mapbox.satellite out.png
      $ mapbox staticmap --lon -61.7 --lat 12.1 --zoom 12 mapbox.satellite out2.png

    An access token is required, see `mapbox --help`.
    """
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    if features:
        features = list(
            cligj.normalize_feature_inputs(None, 'features', [features]))

    service = mapbox.Static(access_token=access_token)

    try:
        res = service.image(mapid,
                            lon=lon,
                            lat=lat,
                            z=zoom,
                            width=size[0],
                            height=size[1],
                            features=features,
                            sort_keys=True)
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        output.write(res.content)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #2
0
def surface(ctx, mapid, layer, fields, features, zoom, interpolate, geojson,
            output):
    """Mapbox Surface API enables flexible querying of data stored in
vector tiles on Mapbox, to create results like elevation profiles.

      $ mapbox surface mapbox.mapbox-terrain-v1 contour ele \\
\b
            "[-122.781, 45.528]" "[-122.716, 45.525]"

An access token is required, see `mapbox --help`.
    """
    stdout = click.open_file(output, 'w')
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    fields = fields.split(",")

    service = mapbox.Surface(access_token=access_token)

    try:
        res = service.surface(features,
                              mapid=mapid,
                              layer=layer,
                              fields=fields,
                              geojson=geojson,
                              interpolate=interpolate,
                              zoom=zoom)
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        if geojson:
            click.echo(json.dumps(res.geojson()), file=stdout)
        else:
            click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #3
0
def create_tileset(ctx, dataset, tileset, name):
    """Create a vector tileset from a dataset.

        $ mapbox datasets create-tileset dataset-id username.data

    Note that the tileset must start with your username and the dataset
    must be one that you own. To view processing status, visit
    https://www.mapbox.com/data/. You may not generate another tilesets
    from the same dataset until the first processing job has completed.

    All endpoints require authentication. An access token with
    `uploads:write` scope is required, see `mapbox --help`.
    """

    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    service = mapbox.Uploader(access_token=access_token)

    uri = "mapbox://datasets/{username}/{dataset}".format(
        username=tileset.split('.')[0], dataset=dataset)

    res = service.create(uri, tileset, name)

    if res.status_code == 201:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #4
0
def match(ctx, features, profile, gps_precision):
    """Mapbox Map Matching API lets you use snap your GPS traces
to the OpenStreetMap road and path network.

      $ mapbox mapmatching trace.geojson

An access token is required, see `mapbox --help`.
    """
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None

    features = list(features)
    if len(features) != 1:
        raise click.BadParameter(
            "Mapmatching requires a single LineString feature")

    service = mapbox.MapMatcher(access_token=access_token)
    try:
        res = service.match(features[0],
                            profile=profile,
                            gps_precision=gps_precision)
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        stdout = click.open_file('-', 'w')
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #5
0
def directions(ctx, features, geojson, profile, alternatives,
               instructions, geometry, steps, output):
    """Calculate optimal route with turn-by-turn directions
    between up to 25 waypoints.

      $ mapbox directions "[-122.681032, 45.528334]" "[-122.71679, 45.525135]"

    An access token is required, see `mapbox --help`.
    """
    stdout = click.open_file(output, 'w')
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    if geojson:
        geometry = 'geojson'

    service = mapbox.Directions(access_token=access_token)

    try:
        res = service.directions(
            features,
            steps=steps,
            alternatives=alternatives,
            instructions=instructions,
            geometry=geometry,
            profile=profile)
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        if geojson:
            click.echo(json.dumps(res.geojson()), file=stdout)
        else:
            click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #6
0
def batch_update_features(ctx, dataset, puts, deletes, input):
    """Update features of a dataset.

    Up to 100 features may be deleted or modified in one request. PUTS
    should be a JSON array of GeoJSON features to insert or updated.
    DELETES should be a JSON array of feature ids to be deleted.

        $ mapbox datasets batch-update-features dataset-id 'puts' 'deletes'

    All endpoints require authentication. An access token with
    `datasets:write` scope is required, see `mapbox --help`.
    """

    if puts:
        puts = json.loads(puts)

    if deletes:
        deletes = json.loads(deletes)

    if puts is None and deletes is None:
        stdin = click.open_file(input, 'r')
        input = json.loads(stdin.read())
        puts = input['put']
        deletes = input['delete']

    service = ctx.obj.get('service')
    res = service.batch_update_features(dataset, puts, deletes)

    if res.status_code == 200:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #7
0
def put_feature(ctx, dataset, fid, feature, input):
    """Create or update a dataset feature.

    The semantics of HTTP PUT apply: if the dataset has no feature
    with the given `fid` a new feature will be created. Returns a
    GeoJSON representation of the new or updated feature.

        $ mapbox datasets put-feature dataset-id feature-id 'geojson-feature'

    All endpoints require authentication. An access token with
    `datasets:write` scope is required, see `mapbox --help`.
    """

    if feature is None:
        stdin = click.open_file(input, 'r')
        feature = stdin.read()

    feature = json.loads(feature)

    service = ctx.obj.get('service')
    res = service.update_feature(dataset, fid, feature)

    if res.status_code == 200:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #8
0
def distance(ctx, features, profile, output):
    """The Distance API returns all travel times between
    many points (also known as Distance Matrix). This is often
    used as input for solving routing optimization problems.

      $ mapbox distance "[-122.681, 45.528]" "[-122.716, 45.525]"

    The output is a json object with a "durations" key
    containing a 2D array of travel times between waypoints.

    An access token is required, see `mapbox --help`.
    """
    stdout = click.open_file(output, 'w')
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    service = mapbox.Distance(access_token=access_token)

    try:
        res = service.distances(
            features,
            profile=profile)
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #9
0
def upload(ctx, args, name):
    """Upload data to Mapbox accounts.
    All endpoints require authentication.
    Uploaded data lands at https://www.mapbox.com/data/
    and can be used in new or existing projects.

    You can specify the input file and tileset id

      $ mapbox upload mydata.geojson username.data

    Or specify just the tileset id and take an input file on stdin

      $ cat mydata.geojson | mapbox upload username.data

    The --name option defines the title as it appears in Studio
    and defaults to the last part of the tileset id, e.g. "data"

    Note that the tileset must start with your username.
    An access token with upload scope is required, see `mapbox --help`.
    """
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None

    service = mapbox.Uploader(access_token=access_token)

    if len(args) == 1:
        # Tileset specified, file from stdin
        click.echo("Reading data from stdin (Hit Ctl-C to cancel) ...",
                   err=True)
        infile = BytesIO(click.File("rb")("-").read())
        tileset = args[0]
    elif len(args) == 2:
        # Infile and Tileset are specified
        try:
            infile = click.File("rb")(args[0])
        except click.ClickException:
            raise click.UsageError(
                "Could not open file: {0} "
                "(check order of command arguments: INFILE TILESET)".format(
                    args[0]))

        tileset = args[1]
    else:
        raise click.UsageError(
            "Must provide either one argument (TILESET) or two (INFILE TILESET)"
        )

    if name is None:
        name = tileset.split(".")[-1]

    try:
        res = service.upload(infile, tileset, name)
    except (mapbox.errors.ValidationError, IOError) as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 201:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #10
0
def directions(ctx, features, profile, alternatives, 
               geometries, overview, steps, continue_straight, 
               waypoint_snapping, annotations, language, output):
    """The Mapbox Directions API will show you how to get
       where you're going.

       mapbox directions "[0, 0]" "[1, 1]"

       An access token is required.  See "mapbox --help".
    """

    access_token = (ctx.obj and ctx.obj.get("access_token")) or None

    service = mapbox.Directions(access_token=access_token)

    # The Directions SDK expects False to be
    # a bool, not a str.

    if overview == "False":
        overview = False

    # When using waypoint snapping, the 
    # Directions SDK expects features to be 
    # a list, not a generator.

    if waypoint_snapping is not None:
        features = list(features)

    if annotations:
        annotations = annotations.split(",")

    stdout = click.open_file(output, "w")

    try:
        res = service.directions(
            features,
            profile=profile,
            alternatives=alternatives,
            geometries=geometries,
            overview=overview,
            steps=steps,
            continue_straight=continue_straight,
            waypoint_snapping=waypoint_snapping,
            annotations=annotations,
            language=language
        )
    except mapbox.errors.ValidationError as exc:
        raise click.BadParameter(str(exc))

    if res.status_code == 200:
        if geometries == "geojson":
            click.echo(json.dumps(res.geojson()), file=stdout)
        else:
            click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #11
0
def delete_feature(ctx, dataset, fid):
    """Delete a feature.

        $ mapbox datasets delete-feature dataset-id feature-id

    All endpoints require authentication. An access token with
    `datasets:write` scope is required, see `mapbox --help`.
    """

    service = ctx.obj.get('service')
    res = service.delete_feature(dataset, fid)

    if res.status_code != 204:
        raise MapboxCLIException(res.text.strip())
Пример #12
0
def update_dataset(ctx, dataset, name, description):
    """Update the name and description of a dataset.

    Prints a JSON object containing the updated dataset
    attributes.

        $ mapbox datasets update-dataset dataset-id

    All endpoints require authentication. An access token with
    `datasets:write` scope is required, see `mapbox --help`.
    """

    service = ctx.obj.get('service')
    res = service.update_dataset(dataset, name, description)

    if res.status_code == 200:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #13
0
def create(ctx, name, description):
    """Create a new dataset.

    Prints a JSON object containing the attributes
    of the new dataset.

        $ mapbox datasets create

    All endpoints require authentication. An access token with
    `datasets:write` scope is required, see `mapbox --help`.
    """

    service = ctx.obj.get('service')
    res = service.create(name, description)

    if res.status_code == 200:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #14
0
def list(ctx, output):
    """List datasets.

    Prints a list of objects describing datasets.

        $ mapbox datasets list

    All endpoints require authentication. An access token with
    `datasets:read` scope is required, see `mapbox --help`.
    """

    stdout = click.open_file(output, 'w')
    service = ctx.obj.get('service')
    res = service.list()

    if res.status_code == 200:
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #15
0
def list_features(ctx, dataset, reverse, start, limit, output):
    """Get features of a dataset.

    Prints the features of the dataset as a GeoJSON feature collection.

        $ mapbox datasets list-features dataset-id

    All endpoints require authentication. An access token with
    `datasets:read` scope is required, see `mapbox --help`.
    """

    stdout = click.open_file(output, 'w')
    service = ctx.obj.get('service')
    res = service.list_features(dataset, reverse, start, limit)

    if res.status_code == 200:
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #16
0
def read_feature(ctx, dataset, fid, output):
    """Read a dataset feature.

    Prints a GeoJSON representation of the feature.

        $ mapbox datasets read-feature dataset-id feature-id

    All endpoints require authentication. An access token with
    `datasets:read` scope is required, see `mapbox --help`.
    """

    stdout = click.open_file(output, 'w')
    service = ctx.obj.get('service')
    res = service.read_feature(dataset, fid)

    if res.status_code == 200:
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #17
0
def read_dataset(ctx, dataset, output):
    """Read the attributes of a dataset.

    Prints a JSON object containing the attributes
    of a dataset. The attributes: owner (a Mapbox account),
    id (dataset id), created (Unix timestamp), modified
    (timestamp), name (string), and description (string).

        $ mapbox datasets read-dataset dataset-id

    All endpoints require authentication. An access token with
    `datasets:read` scope is required, see `mapbox --help`.
    """

    stdout = click.open_file(output, 'w')
    service = ctx.obj.get('service')
    res = service.read_dataset(dataset)

    if res.status_code == 200:
        click.echo(res.text, file=stdout)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #18
0
def upload(ctx, tileset, datasource, name, patch):
    """Upload data to Mapbox accounts.

    Uploaded data lands at https://www.mapbox.com/data/ and can be used
    in new or existing projects. All endpoints require authentication.

    You can specify the tileset id and input file

      $ mapbox upload username.data mydata.geojson

    Or specify just the tileset id and take an input file on stdin

      $ cat mydata.geojson | mapbox upload username.data

    The --name option defines the title as it appears in Studio and
    defaults to the last part of the tileset id, e.g. "data"

    Note that the tileset must start with your username. An access
    token with upload scope is required, see `mapbox --help`.

    Your account must be flagged in order to use the patch mode
    feature.
    """
    access_token = (ctx.obj and ctx.obj.get('access_token')) or None

    service = mapbox.Uploader(access_token=access_token)

    if name is None:
        name = tileset.split(".")[-1]

    if datasource.startswith('https://'):
        # Skip staging. Note this this only works for specific buckets.
        res = service.create(datasource, tileset, name=name, patch=patch)

    else:
        sourcefile = click.File('rb')(datasource)

        if hasattr(sourcefile, 'name'):
            filelen = (1 if sourcefile.name == '<stdin>' else os.stat(
                sourcefile.name).st_size)
        else:
            filelen = (len(sourcefile.getbuffer()) if hasattr(
                sourcefile, 'getbuffer') else 1)

        with click.progressbar(length=filelen,
                               label='Uploading data source',
                               fill_char="#",
                               empty_char='-',
                               file=sys.stderr) as bar:

            def callback(num_bytes):
                """Update the progress bar"""
                bar.update(num_bytes)

            res = service.upload(sourcefile,
                                 tileset,
                                 name,
                                 patch=patch,
                                 callback=callback)

    if res.status_code == 201:
        click.echo(res.text)
    else:
        raise MapboxCLIException(res.text.strip())
Пример #19
0
def geocoding(ctx, query, forward, include_headers, lat, lon,
              place_type, output, dataset, country, bbox, features, limit):
    """This command returns places matching an address (forward mode) or
    places matching coordinates (reverse mode).

    In forward (the default) mode the query argument shall be an address
    such as '1600 pennsylvania ave nw'.

      $ mapbox geocoding '1600 pennsylvania ave nw'

    In reverse mode the query argument shall be a JSON encoded array
    of longitude and latitude (in that order) in decimal degrees.

      $ mapbox geocoding --reverse '[-77.4371, 37.5227]'

    An access token is required, see `mapbox --help`.
    """
    verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 2
    logger = logging.getLogger('mapbox')

    access_token = (ctx.obj and ctx.obj.get('access_token')) or None
    stdout = click.open_file(output, 'w')

    geocoder = mapbox.Geocoder(name=dataset, access_token=access_token)

    if forward:
        if country:
            country = [x.lower() for x in country.split(",")]

        if bbox:
            try:
                bbox = tuple(map(float, bbox.split(',')))
            except ValueError:
                bbox = json.loads(bbox)

        for q in iter_query(query):
            try:
                resp = geocoder.forward(
                    q, types=place_type, lat=lat, lon=lon,
                    country=country, bbox=bbox, limit=limit)
            except mapbox.errors.ValidationError as exc:
                raise click.BadParameter(str(exc))

            if include_headers:
                echo_headers(resp.headers, file=stdout)
            if resp.status_code == 200:
                if features:
                    collection = json.loads(resp.text)
                    for feat in collection['features']:
                        click.echo(json.dumps(feat), file=stdout)
                else:
                    click.echo(resp.text, file=stdout)
            else:
                raise MapboxCLIException(resp.text.strip())
    else:
        for lon, lat in map(coords_from_query, iter_query(query)):
            try:
                resp = geocoder.reverse(
                    lon=lon, lat=lat, types=place_type, limit=limit)
            except mapbox.errors.ValidationError as exc:
                raise click.BadParameter(str(exc))

            if include_headers:
                echo_headers(resp.headers, file=stdout)
            if resp.status_code == 200:
                if features:
                    collection = json.loads(resp.text)
                    for feat in collection['features']:
                        click.echo(json.dumps(feat), file=stdout)
                else:
                    click.echo(resp.text, file=stdout)
            else:
                raise MapboxCLIException(resp.text.strip())