2

I am getting the following error on this function:

ValueError: Record's geometry type does not match collection schema's geometry type: 'Point' != 'MultiPoint'

The problem is that I have multipoints mixed with regular points. When I try to write the outputs at I get a schema confusion problem

The record causing problems at 'output.write' is this one (note: that for a MultiPoint it only has one x,y):

{'geometry': {'type': 'MultiPoint', 'coordinates': [(13531245.475704141, 2886003.2689278126)]}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'H20Status', u'Fair')])}

When I go:

                        if geom['type'] == 'MultiPoint':
                        # break Multipoints into points
                        # i.e. <class 'shapely.geometry.multipoint.MultiPoint'>

                            for pt in my_shape:
                                pt = self.move_point(pt, compare, dist)

'pt' becomes a 'Point':

POINT (13531245.47570414 2886003.268927813)

Then when I try to write it back to what it was (a Multipoint):

                    # write to outfile - WHERE EVERYTHING FAILS
                    output.write({'geometry':mapping(pt), 'properties': item['properties']})

I get this:

ValueError: Record's geometry type does not match collection schema's geometry type: 'Point' != 'MultiPoint'

If I try to re-write 'pt' to a 'MultiPoint' BEFORE the write operation (and again, this is a multipoint with ONE coordinate set) like so,

 mpoint = MultiPoint(pt)

I get this:

  File "C:\Python27\lib\site-packages\shapely\geometry\multipoint.py", line 143, in geos_multipoint_from_py
    assert len(array['shape']) == 2
AssertionError

*Full working code after help from @gene and @Vince *

def process_file(self, in_file, out_file, compare_file, dist):
    # open input file and compare file
    # loop over each
    with fiona.open(in_file, 'r') as input:
        meta = input.meta
        # The outFile has the same crs, schema as inFile
        with fiona.open(out_file, 'w', **meta) as output:
            with fiona.open(compare_file, 'r') as compare:
            # Read shapely geometries from file
            # Loop through all shapely objects
            # type(item) = 'dict'
                for item in input:
                    geom = item['geometry']
                    my_shape = shape(geom)

                    # check if it is a multipoint or point
                    if geom['type'] == 'MultiPoint':
                        # break Multipoints into points
                        # i.e. <class 'shapely.geometry.multipoint.MultiPoint'>

                        for pt in my_shape:
                            single_point = self.move_point(pt, compare, dist)
                            mpoint = MultiPoint([(single_point.x, single_point.y)])
                            mpoint_for_merge = shape(mapping(mpoint))
                            # write to outfile - WHERE EVERYTHING NOW WORKS
                            output.write({'geometry':mapping(mpoint_for_merge), 'properties': item['properties']})

                    elif geom['type'] == 'Point':
                        # return of move_point is a shapely geom
                        # i.e. <class 'shapely.geometry.point.Point'>
                        my_shape = self.move_point(my_shape, compare, dist)
                        # write to outfile
                        output.write({'geometry':mapping(my_shape), 'properties': item['properties']})

                    else:
                        raise ValueError('unhandled geometry type: ' + repr(geom.type))
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
user14696
  • 497
  • 1
  • 7
  • 16
  • 1
    Point and multipoint objects are distinct record types; shapefiles will only permit one or the other. The workaround is to make "multipoint" objects with a count of 1. You wouldn't want to do this if ALL features were single-point, since the envelope search algorithm isn't as effective as the point search protocol, but if you have a mixture you don't have a choice. – Vince Mar 24 '15 at 17:39
  • Fiona enables to save MultiPoint geometries (there are transformed by the module) – gene Mar 24 '15 at 17:58
  • @Vince I think you are right. I try to write a 1 pt multipoint though...and I get a error. No probs reading it. Error above./ – user14696 Mar 24 '15 at 20:14
  • 1
    Singleton multipoints are somewhat esoteric, so the framework may not have been tested for that case (I had 4 year old shape-writing source that had this wrong the whole time, so I know it could happen). I'm not familiar with Fiona, just the shapefile spec. – Vince Mar 24 '15 at 21:12
  • geopandas now has a method for doing this gpd.explode() – zelusp Apr 17 '19 at 21:05

1 Answers1

3

Keep things simple, a MultiPoint is a simple list of Points and the type of geometry can be obtained by Fiona (key ['geometry']['type']) of by Shapely (geometry.type)

with fiona.open(in_file, 'r') as input:
   with fiona.open(compare_file, 'r') as compare:
       meta = input.meta
       with fiona.open(out_file, 'w', **meta) as output:
          for item in input:
              geom = item['geometry']
              my_shape = shape(geom)
              # check if it is a Multipoint 
              if geom['type'] == 'MultiPoint':
                  for pt in my_shape:
                       my_shape = self.move_point(pt, compare, dist)
              else: # the Points
                   my_shape = self.move_point(my_shape, compare, dist)

You can also use

if my_shape.type == 'MultiPoint':

New

Your problem is to transform a Point into a MultiPoint. With Shapely you need to use the coordinates of the Point and not the Point itself (look at Collections of Points)

Multi = MultiPoint([(13531245.475704141, 2886003.2689278126)])
print Multi
MULTIPOINT (13531245.47570414 2886003.268927813)
point = Multi[0]
print point
POINT (13531245.47570414 2886003.268927813)

Now, you can't use mpoint = MultiPoint(point) but

mpoint = MultiPoint([(point.x, point.y)])
print mapping(mpoint)
{'type': 'MultiPoint', 'coordinates': ((13531245.475704141, 2886003.2689278126),)}
# and
print shape(mapping(mpoint))
MULTIPOINT (13531245.47570414 2886003.268927813)
gene
  • 54,868
  • 3
  • 110
  • 187