mapshaper icon indicating copy to clipboard operation
mapshaper copied to clipboard

What is the proper way for "drop polyline layer if present"

Open matkoniecz opened this issue 4 years ago • 2 comments

I have a dataset that is supposed to contain only areas, in case of polylines being present my program should complain loudly and discard polylines.

As first step I tried: mapshaper -i combine-files in.geojson -target type=polyline -drop -o out.geojson

But in case of valid data it will error with [target] Error: No layers were matched (pattern: * type: polyline)

In addition it seems that there is no good way to check (by script) whatever given layer is present in the first place.

It seems that to solve need I will need to iterate over geojson using some other tool (what may be needed anyway to list offending lines). Or is it possible to do it with Mapshaper itself? I am likely missing something but I am staring at documentation and unable to discover what is going wrong.

matkoniecz avatar Feb 20 '21 22:02 matkoniecz

This issue is related to the question of how to process files that are inconsistent or heterogeneous in some way. In this case, some of your files contain polyline features and others don't. I've had this problem in my work too.

I can think of a few possible solutions, but they all require writing some new code.

One solution could be to allow null (or missing) command targets, and skip running any commands with a null target. This would allow your example command (mapshaper -i combine-files in.geojson -target type=polyline -drop -o out.geojson) to run, although it wouldn't complain the way you want.

Another solution i've thought about is to add "flow control" commands, which would run a set of commands if a certain condition is met. Flow control commands might have names like -if -elif -else and -endif (or -fi). It could work like this:

mapshaper in.geojson \
  -if 'target.type == "polyline"' \
  -drop \
  -endif \
  -o out.geojson

Another solution would be to write a new command line program for testing if a GeoJSON file satisfies a variety of conditions. You could use such a program in shell scripts to conditionally run mapshaper (or another CLI program, like ogr2ogr). This approach would have the advantage of working with any command line program that accepts GeoJSON input. You could use it like this:

if geojson-test data.geojson --has-linestrings ; then \
    echo STRIPPING POLYLINES; \
    mapshaper data.geojson -target type=polyline -drop -o data.geojson force \
fi

mbloch avatar Feb 22 '21 05:02 mbloch

Thanks for reply and confirmation that I am not missing something in docs/code. If anyone is curious following is my Ruby-based solution (not truly universal, assumes single geometry collection without nesting). (feel free to delete/edit this comment if it is offtopic).

def keep_area_only(input_geojson_file, output_geojson)
  # https://github.com/rgeo/rgeo-geojson/issues/51
  # https://github.com/mbloch/mapshaper/issues/463
  assert_that_file_exists(input_geojson_file)
  geojson_text = File.open(input_geojson_file).read
  geom = JSON.parse(geojson_text)
  # assumes one feature collection, collecting directly all geometries
  if geom["type"] != "FeatureCollection"
    raise "unexpected structure, #{geom["type"]} unexpectedly appeared"
  end
  only_areas = true
  geom["features"].each do |element|
    if ["Polygon", "MultiPolygon"].include?(element["geometry"]["type"]) == false
      puts "Not an area! #{element["geometry"]["type"]}"
      only_areas = false
    end
  end
  command = "mapshaper -i combine-files #{input_geojson_file} -target type=polyline -drop -o #{output_geojson}"
  if only_areas
    command = "mapshaper -i combine-files #{input_geojson_file} -o combine-layers #{output_geojson}"
  end
  execute_command(command)
  assert_that_file_exists(output_geojson, "executing: " + command)
  detect_unexpected_datatypes(output_geojson, areas_expected: true)
end

If anyone cares, code above is CC0/MIT licensed.

matkoniecz avatar Feb 22 '21 08:02 matkoniecz