Skip to content

Commit 0b2ce07

Browse files
committed
Support feature refs as strings
1 parent 8a9c4b6 commit 0b2ce07

File tree

10 files changed

+164
-62
lines changed

10 files changed

+164
-62
lines changed

docs/cli/cli-tips-tricks.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@ title: More CLI Tips & Tricks
55
## About
66

77
This document shows off a range of more advanced command-line workflows, making use of a wider range
8-
of tools in the command-line & geospatial ecosystem. Some of them can be a pain to install, like
9-
GDAL/OGR, and several pop in and out of web tools, so these are kept out of the main tutorial
10-
section.
8+
of tools in the command-line & geospatial ecosystem. Some of them can be a pain to install, like
9+
GDAL/OGR, and several pop in and out of web tools, so these are kept out of the main tutorial
10+
section.
1111

1212
**WORK IN PROGRESS**: This document is still under construction, with a number of TODO’s remaining,
1313
but we are publishing as there’s a lot of good information here.
1414

1515
## Tools used
1616

17-
* **[GDAL/OGR](https://gdal.org)** - We’ll mostly use OGR, the vector tooling.
17+
* **[GDAL/OGR](https://gdal.org)** - We’ll mostly use OGR, the vector tooling.
1818
Great for things like format conversion and basic simplification.
1919
* **[Keplergl_cli](https://github.com/kylebarron/keplergl_cli#usage)** - Nice tool to call the
20-
awesome kepler.gl library from the commandline. Useful for visualization of large amounts of
20+
awesome kepler.gl library from the commandline. Useful for visualization of large amounts of
2121
geojson.
2222
* **[GeoJSON.io](https://geojson.io/)** - Simple tool to do editing of geojson, useful for creating
2323
AOI’s. It integrates with github, but the ability to save a GeoJSON to github doesn't seem to work so well.
2424
* **[Placemark.io](https://placemark.io)** - More advanced tool from the creator of GeoJSON.io, very
25-
nice for creating AOI’s and piping them in, with lots of rich geometry editing features.
25+
nice for creating AOI’s and piping them in, with lots of rich geometry editing features.
2626
* **[MapShaper](https://github.com/mbloch/mapshaper)** - Tool to do interactive simplification of
2727
GeoJSON, has a nice CLI.
2828
* **[STACTools](https://github.com/stac-utils/stactools)** - CLI for working with STAC data. There
@@ -34,26 +34,28 @@ future.
3434

3535
### Geometry Inputs
3636

37-
While the command-line can often be quicker than using a UI, one place that can be slower is
37+
While the command-line can often be quicker than using a UI, one place that can be slower is
3838
getting the geometry input for searching or clipping. Hand-editing GeoJSON is a huge pain, so most
39-
people will open up a desktop tool like QGIS or ArcGIS Pro and save the file. But there are a few
39+
people will open up a desktop tool like QGIS or ArcGIS Pro and save the file. But there are a few
4040
tools that can get you back into the CLI workflow more quickly.
4141

4242
#### Use the Features API
4343
Rather than using GeoJSON in the SDK, upload your GeoJSON to the [Features API](https://developers.planet.com/docs/apis/features/) and use references
4444
across the system with the sdk.
45-
References are used in the geometry block of our services like:
45+
References are used in the geometry block of our services in a GeoJSON blob like:
4646
```json
4747
"geometry":
4848
{
4949
"content": "pl:features/my/[collection-id]/[feature-id]",
5050
"type": "ref"
5151
}
5252
```
53+
Or as a string in a geometry option like `"pl:features/my/[collection-id]/[feature-id]"`
54+
5355

5456
#### Draw with GeoJSON.io
5557

56-
One great tool for quickly drawing on a map and getting GeoJSON output is
58+
One great tool for quickly drawing on a map and getting GeoJSON output is
5759
[GeoJSON.io](https://geojson.io). You can draw and save the file, but an even faster workflow
5860
is to use your operating system’s clipboard to command-line tools.
5961

@@ -74,7 +76,7 @@ pbpaste | planet data filter --geom - | planet data search SkySatCollect --filt
7476

7577
A really fantastic tool for working with GeoJSON is [Placemark](https://placemark.io). It is a
7678
commercial tool that you’ll have to pay for, but it’s got a really nice feature that makes it very
77-
compatible with command-line workflows. You can easily grab the URL of any individual GeoJSON
79+
compatible with command-line workflows. You can easily grab the URL of any individual GeoJSON
7880
feature and stream it in as your geometry using `curl`:
7981

8082
![Stream from Placemark](https://user-images.githubusercontent.com/407017/179412209-2365d79a-9260-47e5-9b08-9bc5b84b6ddc.gif)
@@ -92,8 +94,8 @@ let you pipe (`|`) the output more directly.
9294

9395
#### Copy GeoJSON to clipboard
9496

95-
One of the quicker routes to visualizing search output is to copy the output to your clipboard and paste into a
96-
tool that will take GeoJSON and visualize it.
97+
One of the quicker routes to visualizing search output is to copy the output to your clipboard and paste into a
98+
tool that will take GeoJSON and visualize it.
9799

98100
You can do this on GeoJSON.io:
99101

@@ -113,7 +115,7 @@ planet data filter --string-in strip_id 5743669 | planet data search PSScene --f
113115

114116
#### Post to Github as gist
115117

116-
Another easy option that is a bit more persistent is to post to Github using the
118+
Another easy option that is a bit more persistent is to post to Github using the
117119
[`gh` cli tool](https://github.com/cli/cli). Specifically using the `gist create` command.
118120

119121
The following command will get the latest SkySat image captured, upload to github, and open
@@ -147,13 +149,13 @@ planet data filter --string-in strip_id $stripid | planet data search PSScene --
147149

148150
One of the best tools to visualize large numbers of imagery footprints is a tool called [kepler.gl](https://kepler.gl/),
149151
which has a really awesome command-line version which is perfect for working with Planet’s CLI. To get the CLI go to
150-
[keplergl_cli](https://github.com/kylebarron/keplergl_cli) and follow the
152+
[keplergl_cli](https://github.com/kylebarron/keplergl_cli) and follow the
151153
[installation instructions](https://github.com/kylebarron/keplergl_cli#install). Be sure to get a Mapbox API key (from
152154
the [access tokens](https://account.mapbox.com/access-tokens/) page) - just sign up for a free account if you don't have
153155
one already. The kepler CLI won't work at all without getting one and setting it as the `MAPBOX_API_KEY` environment
154156
variable.
155157

156-
Once it’s set up you can just pipe any search command directly to `kepler` (it usually does fine even without
158+
Once it’s set up you can just pipe any search command directly to `kepler` (it usually does fine even without
157159
`planet collect` to go from ndgeojson to geojson). For example:
158160

159161
```console
@@ -191,9 +193,9 @@ curl -s https://api.placemark.io/api/v1/map/a0BWUEErqU9A1EDHZWHez/feature/91a073
191193

192194
#### Large Dataset Visualization
193195

194-
Oftentimes it can be useful to visualize a large amount of data, to really get a sense of the
195-
coverage and then do some filtering of the output. For this we recommend downloading the output
196-
to disk. Getting 20,000 skysat collects will take at least a couple of minutes, and will be over
196+
Oftentimes it can be useful to visualize a large amount of data, to really get a sense of the
197+
coverage and then do some filtering of the output. For this we recommend downloading the output
198+
to disk. Getting 20,000 skysat collects will take at least a couple of minutes, and will be over
197199
100 megabytes of GeoJSON on disk.
198200

199201
```console
@@ -267,7 +269,7 @@ Smaller ratios preserve the character of concave features better.
267269

268270
##### Simplification with OGR
269271

270-
The other thing you’ll likely want to do to visualize large amounts of data is to simplify it
272+
The other thing you’ll likely want to do to visualize large amounts of data is to simplify it
271273
some. Many simplification tools call for a 'tolerance', often set in degrees. For SkySat some useful values are:
272274

273275
| tolerance | result |
@@ -276,7 +278,7 @@ some. Many simplification tools call for a 'tolerance', often set in degrees. Fo
276278
| 0.01 | Messes with the shape a bit, but the footprint generally looks the same, with a couple vertices off. |
277279
| 0.1 | Mashes the shape, often into a triangle, but still useful for understanding broad coverage. |
278280

279-
It’s worth experimenting with options between these as well. The more simplification the easier it is for programs to
281+
It’s worth experimenting with options between these as well. The more simplification the easier it is for programs to
280282
render the results. `ogr2ogr` includes the ability to simplify any output:
281283

282284
```console
@@ -289,14 +291,14 @@ Alternative - use convex hull. TODO: test this, write it up
289291
ogr2ogr skysat-convex.gpkg skysat.geojson ogr2ogr -sql "select st_convexhull(geometry) from skysat" -dialect sqlite
290292
```
291293

292-
Other alternative for really big ones, centroid. GDAL should be able to do this, need to figure out the similar
294+
Other alternative for really big ones, centroid. GDAL should be able to do this, need to figure out the similar
293295
sql.
294296

295297
#### Simplification with Mapshaper
296298

297-
Another great tool is [Mapshaper](https://github.com/mbloch/mapshaper), which excels at simplification. It offers a
298-
web-based user interface to see the results of simplification, and also a command-line tool you can use if you
299-
find a simplification percentage you’re happy with. After you get it
299+
Another great tool is [Mapshaper](https://github.com/mbloch/mapshaper), which excels at simplification. It offers a
300+
web-based user interface to see the results of simplification, and also a command-line tool you can use if you
301+
find a simplification percentage you’re happy with. After you get it
300302
[installed](https://github.com/mbloch/mapshaper#installation) you can fire up the UI with:
301303

302304
```console
@@ -312,13 +314,13 @@ interface, or you can also run the command-line program:
312314
mapshaper -i footprints.geojson -simplify 15% -o simplified.geojson
313315
```
314316

315-
Once you find a simplification amount you’re happy with you can use it as a piped output.
317+
Once you find a simplification amount you’re happy with you can use it as a piped output.
316318

317319
```console
318320
planet data search --limit 20 SkySatCollect - | planet collect - | mapshaper -i - -simplify 15% -o skysat-ms2.geojson
319321
```
320322

321-
Mapshaper also has more simplification algorithms to try out, so we recommend diving into the
323+
Mapshaper also has more simplification algorithms to try out, so we recommend diving into the
322324
[CLI options](https://github.com/mbloch/mapshaper/wiki/Command-Reference).
323325

324326
#### Simplification with QGIS
@@ -328,7 +330,7 @@ Another good tool for simplification is QGIS.
328330
TODO: Flesh out this section, add in command-line qgis_processing option.
329331

330332
Other simplification options for large datasets:
331-
333+
332334
* Use QGIS, run 'convex hull' (Vector -> Geoprocessing -> Convex Hull). Good idea to convert to gpkg or shapefile before you open in qgis if large.
333335

334336
### Advanced jq
@@ -339,7 +341,7 @@ Other simplification options for large datasets:
339341
- get id by array number
340342

341343
```console
342-
planet orders list | jq -rs '.[3] | "\(.id) \(.created_on) \(.name) \(.state)"'
344+
planet orders list | jq -rs '.[3] | "\(.id) \(.created_on) \(.name) \(.state)"'
343345
```
344346
(limit can get the most recent, but not a second or third)
345347

planet/cli/data.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from typing import List, Optional
1616
from contextlib import asynccontextmanager
1717
from pathlib import Path
18-
1918
import click
2019

2120
from planet.reporting import AssetStatusBar
@@ -81,9 +80,15 @@ def check_item_types(ctx, param, item_types) -> Optional[List[dict]]:
8180
raise click.BadParameter(str(e))
8281

8382

84-
def check_geom(ctx, param, geometry: Optional[dict]) -> Optional[dict]:
83+
def check_geom(ctx, param, geometry) -> Optional[dict]:
8584
"""Validates geometry as GeoJSON or feature ref(s)."""
86-
return geojson.as_geom_or_ref(geometry) if geometry else None
85+
if isinstance(geometry, dict):
86+
return geojson.as_geom_or_ref(geometry)
87+
geoms = {}
88+
if geometry:
89+
for geom in geometry:
90+
geoms.update(geojson.as_geom_or_ref(geom))
91+
return geoms if geoms else None
8792

8893

8994
def check_item_type(ctx, param, item_type) -> Optional[List[dict]]:
@@ -286,7 +291,7 @@ def filter(ctx,
286291
@click.argument("item_types",
287292
type=types.CommaSeparatedString(),
288293
callback=check_item_types)
289-
@click.option("--geom", type=types.JSON(), callback=check_geom)
294+
@click.option("--geom", type=types.Geometry(), callback=check_geom)
290295
@click.option('--filter',
291296
type=types.JSON(),
292297
help="""Apply specified filter to search. Can be a json string,
@@ -332,7 +337,7 @@ async def search(ctx, item_types, geom, filter, limit, name, sort, pretty):
332337
@click.argument("item_types",
333338
type=types.CommaSeparatedString(),
334339
callback=check_item_types)
335-
@click.option("--geom", type=types.JSON(), callback=check_geom)
340+
@click.option("--geom", type=types.Geometry(), callback=check_geom)
336341
@click.option(
337342
'--filter',
338343
type=types.JSON(),
@@ -500,7 +505,10 @@ async def search_delete(ctx, search_id):
500505
type=str,
501506
required=True,
502507
help='Name of the saved search.')
503-
@click.option("--geom", type=types.JSON(), callback=check_geom, default=None)
508+
@click.option("--geom",
509+
type=types.Geometry(),
510+
callback=check_geom,
511+
default=None)
504512
@click.option('--daily-email',
505513
is_flag=True,
506514
help='Send a daily email when new results are added.')

planet/cli/subscriptions.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .. import subscription_request
1414
from ..subscription_request import sentinel_hub
1515
from ..specs import get_item_types, validate_item_type, SpecificationException
16+
from planet import geojson
1617

1718
ALL_ITEM_TYPES = get_item_types()
1819
valid_item_string = "Valid entries for ITEM_TYPES: " + "|".join(ALL_ITEM_TYPES)
@@ -29,6 +30,17 @@ def check_item_types(ctx, param, item_types) -> Optional[List[dict]]:
2930
raise click.BadParameter(str(e))
3031

3132

33+
def check_geom(ctx, param, geometry) -> Optional[dict]:
34+
"""Validates geometry as GeoJSON or feature ref(s)."""
35+
if isinstance(geometry, dict):
36+
return geojson.as_geom_or_ref(geometry)
37+
geoms = {}
38+
if geometry:
39+
for geom in geometry:
40+
geoms.update(geojson.as_geom_or_ref(geom))
41+
return geoms if geoms else None
42+
43+
3244
def check_item_type(ctx, param, item_type) -> Optional[List[dict]]:
3345
"""Validates the item type provided by comparing it to all supported
3446
item types."""
@@ -346,7 +358,8 @@ def request(name,
346358
@click.option(
347359
'--geometry',
348360
required=True,
349-
type=types.JSON(),
361+
type=types.Geometry(),
362+
callback=check_geom,
350363
help="""Geometry of the area of interest of the subscription that will be
351364
used to determine matches. Can be a string, filename, or - for stdin.""")
352365
@click.option('--start-time',
@@ -418,7 +431,8 @@ def request_catalog(item_types,
418431
@click.option(
419432
'--geometry',
420433
required=True,
421-
type=types.JSON(),
434+
type=types.Geometry(),
435+
callback=check_geom,
422436
help="""Geometry of the area of interest of the subscription that will be
423437
used to determine matches. Can be a string, filename, or - for stdin.""")
424438
@click.option('--start-time',
@@ -437,6 +451,7 @@ def request_pv(var_type, var_id, geometry, start_time, end_time, pretty):
437451
Variables](https://developers.planet.com/docs/subscriptions/pvs-subs/#planetary-variables-types-and-ids)
438452
for details.
439453
"""
454+
# print("Geom is", geometry)
440455
res = subscription_request.planetary_variable_source(
441456
var_type,
442457
var_id,

planet/cli/types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ def convert(self, value, param, ctx) -> dict:
9393
return convdict
9494

9595

96+
class Geometry(click.ParamType):
97+
name = 'geom'
98+
99+
def __init__(self):
100+
self.types = [JSON(), CommaSeparatedString()]
101+
102+
def convert(self, value, param, ctx):
103+
for type in self.types:
104+
try:
105+
return type.convert(value, param, ctx)
106+
except click.BadParameter:
107+
continue
108+
109+
96110
class Field(click.ParamType):
97111
"""Clarify that this entry is for a field"""
98112
name = 'field'

0 commit comments

Comments
 (0)