3

I am struggling to create a shp and I want it to writes records on the attribute table. I can create the shp but I can not fill in with the correct records. I import an Excel file, that contains the fields "code", "x_Start", "y_Start", "x_Finish", "y_Finish" and I want the field 'code' on the shp table.

Here is the code:

import pandas as pd
import geopandas as gpd
import requests
from shapely.geometry import Point


#import excel
import requests
df = pd.read_excel("NI.xls")
df.head()

#then I create trajectories through an API and I get a list. 

a = list(zip(*[list(df['x_S']), list(df['y_S']), list(df['x_F']), list(df['y_F'])]))
#print (a)
b = [bb for bb in [create_trajectory(coords) for coords in a] if not bb is None]
dg = pd.DataFrame(b)
dg

#I can create the shp from dg but I can't know how to fill in the attribute with th df. Ν.Β. that I do not get the same number routes as I give on excel file.

import shapefile

# Create a polyline shapefile writer
with shapefile.Writer("shapefiles/test/routeNI6") as w:
    #w = shapefile.Writer(shapefile.POLYLINE)

    # Add our fields
    w.field("NAME", "C", "40")


    #lines = []
    for i, row in df.iterrows():
        w.record(df.code)


        w.line([list(row.dropna())])

I want to add only the 'code' records. and here are the errors that I get

TypeError                                 Traceback (most recent call last)
<ipython-input-115-04aa2ea41a9f> in <module>
     21 
---> 22         w.line([list(row.dropna())])

~\Anaconda3\lib\site-packages\shapefile.py in line(self, lines)
   1670         shapeType = POLYLINE
-> 1671         self._shapeparts(parts=lines, shapeType=shapeType)
   1672 

~\Anaconda3\lib\site-packages\shapefile.py in _shapeparts(self, parts, shapeType)
   1756                 if not isinstance(point, list):
-> 1757                     point = list(point)
   1758                 polyShape.points.append(point)

TypeError: 'float' object is not iterable

During handling of the above exception, another exception occurred:

ShapefileException                        Traceback (most recent call last)
<ipython-input-115-04aa2ea41a9f> in <module>
     20         #lines.append(list(row))
     21 
---> 22         w.line([list(row.dropna())])

~\Anaconda3\lib\site-packages\shapefile.py in __exit__(self, exc_type, exc_val, exc_tb)
   1099         Exit phase of context manager, finish writing and close the files.
   1100         """
-> 1101         self.close()
   1102 
   1103     def __del__(self):

~\Anaconda3\lib\site-packages\shapefile.py in close(self)
   1120                 raise ShapefileException("When saving both the dbf and shp file, "
   1121                                          "the number of records (%s) must correspond "
-> 1122                                          "with the number of shapes (%s)" % (self.recNum, self.shpNum))
   1123         # Fill in the blank headers
   1124         if self.shp and shp_open:

ShapefileException: When saving both the dbf and shp file, the number of records (1) must correspond with the number of shapes (0)

I have added the libraries that I use. Actually, I have some couple of thousand polylines. This code is a part of the whole code.

I import the excel file as df and then I create trajectories as dg. So I want to create a shp with features from the dg and to fill in the attribute from df. I hope it helps. I am sorry for the inconvenience but I am quite fresh.

  • and what exactly is the error you get? – zwnk Jul 30 at 20:57
  • 1
    first of all, if you want to have NAME, X and Y seperated you need to add 3 fields: w.field("NAME", "C", "40") w.field('X', 'N', decimal=10) w.field('Y', 'N', decimal=10) assuming your excel input has NAME, X and Y in one line, you need to split them and insert them into the different fields. – zwnk Jul 30 at 21:05
  • 1
    the second error occures because your shapefile dosn't contain a geometry. what is w.line([list(row.dropna())]) doing? – zwnk Jul 30 at 21:56
3

Your code has several issues. First one, 'read_excel' method belongs pandas library and this is not reflected in your question. Additionally, you need to define how many features has your shapefile.POLYLINE. Assuming a polyline with two features, I created a xls file named NI.xls with field code and only two records. So, I also need to define points for each feature:

[-40.5, -20.666],[-39.849998, -18.700001]
[-39.849998, -18.700001],[-39.816002, -19.6]

For avoiding projection issues, I assumed the data for EPSG 4326.

So, with all above assumptions, my code looks as follow:

import shapefile
import pandas as pd

df = pd.read_excel("NI.xls")

df.head()

w = shapefile.Writer(shapefile.POLYLINE)
w.line(parts=[[[-40.5, -20.666],[-39.849998, -18.700001]]])
w.poly(parts=[[[-39.849998, -18.700001],[-39.816002, -19.6]]], shapeType=shapefile.POLYLINE)
w.field('code','C','40')

for i, row in df.iterrows():
    w.record(str(row[0]))

filename = "/home/zeito/pyqgis_data/routeNI7"

w.save(filename)

prj = open("%s.prj" % filename, "w")
epsg = 'GEOGCS["WGS 84",'
epsg += 'DATUM["WGS_1984",'
epsg += 'SPHEROID["WGS 84",6378137,298.257223563]]'
epsg += ',PRIMEM["Greenwich",0],'
epsg += 'UNIT["degree",0.0174532925199433]]'
prj.write(epsg)
prj.close()

After running it at Python Console, I got expected result:

enter image description here

Editing Note:

By using osr osgeo python module, it is easier to define shapefile projection from EPSG:

import shapefile
import pandas as pd
from osgeo import osr

df = pd.read_excel("NI.xls")

df.head()

w = shapefile.Writer(shapefile.POLYLINE)
w.line(parts=[[[-40.5, -20.666],[-39.849998, -18.700001]]])
w.poly(parts=[[[-39.849998, -18.700001],[-39.816002, -19.6]]], shapeType=shapefile.POLYLINE)
w.field('code','C','40')

for i, row in df.iterrows():
    w.record(str(row[0]))

filename = "/home/zeito/pyqgis_data/routeNI7"

w.save(filename)

add_prj = open("%s.prj" % filename, "w")

proj = osr.SpatialReference()
proj.ImportFromEPSG(4326)
epsg = proj.ExportToWkt()

add_prj.write(epsg)
add_prj.close()
  • Hi @xunilk and thank you for your comment. I continue to get errors. Could you please clarify to me how I can use your suggestion? – George Aug 1 at 13:33
  • I ran it in python console of QGIS 2,18 installed in a Linux Debian 8 stable. In QGIS 3.4, in a Linux Debian 9 stable, there is an issue with pyshp module (reported bug). What kind of systen do you use? – xunilk Aug 1 at 17:33
  • I am running the code by Jupyter in Windows – George Aug 1 at 19:56
  • I'll try to run my code in Windows 10 with python 3.7. – xunilk Aug 1 at 22:25
  • I tried my code out in Windows without any success. I searched for possibles issues and it is probably due a bug in pyshp module (bug is referred in several comments). This line: w=shapefile.Writer(shapefile.POLYLINE) produces an unexpected AttributeError. This error is not produced in old python 2.7 with old versions of pyshp. I suggest to use another module instead pyshp. – xunilk Aug 2 at 2:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.