2

EDIT: I've tried running the code linked in the duplicate flag, it's posted here for reference, and it doesn't run. I had already referred to that answer in my initial post.

My problem

Downloaded shapefile is missing .shx file and trying to use pyshp to build it on a mac.*

I've tried this code that I've picked up from the pyshp documentation. When checking the r.shapes and r.records, it looks like all of the info is there.

myshp = open("Stockton/Stockton.shp", "rb")
mydbf = open("Stockton/Stockton.dbf", "rb")
r = shapefile.Reader(shp=myshp, dbf=mydbf, shx=None)

In the documentation, it looks like each record and shape is being added one at a time. Is there a method I'm missing? Or could a list comprehension be used here to loop through everything?**

Data and References

I've downloaded the Microsoft Building Data for Stockton CA from here. I've tried to follow the code from the answer here

    # Build a new shx index file
    #Code by Joel Lawhead http://geospatialpython.com/2011/11/generating-shapefile-shx-files.html
    import shapefile
    # Explicitly name the shp and dbf file objects
    # so pyshp ignores the missing/corrupt shx
    myshp = open("Stockton/Stockton.shp", "rb")
    mydbf = open("Stockton/Stockton.dbf", "rb")
    r = shapefile.Reader(shp=myshp, shx=None, dbf=mydbf)
    w = shapefile.Writer(r.shapeType)
    # Copy everything from reader object to writer object
    w._shapes = r.shapes()
    w.records = r.records()
    w.fields = list(r.fields)
    # saving will generate the shx
    w.save("myshape")

but get this error:

TypeError                                 Traceback (most recent call last)
<ipython-input-94-345df1656b96> in <module>
      7 mydbf = open("Stockton/Stockton.dbf", "rb")
      8 r = shapefile.Reader(shp=myshp, shx=None, dbf=mydbf)
----> 9 w = shapefile.Writer(r.shapeType)
     10 # Copy everything from reader object to writer object
     11 w._shapes = r.shapes()

...

TypeError: expected str, bytes or os.PathLike object, not int

*Because I'm using a Mac, none of the solutions here seem like they would work.

**Still fairly new to Python so please forgive wrong/confusing terminology.

Vince
  • 20,017
  • 15
  • 45
  • 64
maxo
  • 21
  • 3
  • I'm not quite sure how this is a duplicate as the question linked doesn't answer my question. I've run that code and posted the error it gives me. – maxo Jul 31 '19 at 22:52
  • 1
    The OGR options should still work on your Mac. OGR is part of GDAL, which can be installed and run on a Mac. There's a bit of a learning curve though. – Son of a Beach Jul 31 '19 at 23:01
  • There exist datasets for which the .shx *cannot* be recovered, like shapefiles with CAD objects in them. The CAD data live in a hole between the documented geometry data, and the size of the hole can only be determined by peeking at the next record start. – Vince Aug 01 '19 at 00:14
  • 1
    I agree, this isn't a dupe. You need to pass a filepath as the first arg, or use keyword args shapefile.Writer(target='path/to/shx', shapeType=r.shapeType) – user2856 Aug 01 '19 at 04:37
  • https://gis.stackexchange.com/help/someone-answers – user2856 Dec 09 '21 at 07:27

1 Answers1

4

That example code you link to looks like it's out of date (for an old version of pyshp).

This works (based on bits and pieces from the docs):

shp = r"path/to/shp"  # NOTE no .shp extension

from shapefile import (Reader, Writer)

try: # Py2 (I haven't actually tested on python 2...) from StringIO import StringIO as IO except ImportError: # Py3 from io import BytesIO as IO

with IO() as shpio, IO() as dbfio: # Don't overwrite existing .shp, .dbf with Reader(shp) as r, Writer(shp=shpio, dbf=dbfio, shx=shp+'.shx') as w: w.fields = r.fields[1:] # skip first deletion field for rec in r.iterShapeRecords(): w.record(*rec.record) w.shape(rec.shape)

user2856
  • 65,736
  • 6
  • 115
  • 196