PyQGIS – Code Works in Python IDE but Not in QGIS Python Editor

pyqgisqgis-3spyder

I have a working python code that runs within the SPYDER IDE, but doesn't work when run from inside the Python console in QGIS. I have checked the QGIS installs and I can see both panda and shapely. The code opens a .csv (extension .mcsv by the creator) and creates a Polygon from it.

from PyQt5 import QtWidgets
import pandas as pd
from shapely.geometry import Polygon


import_file_path, _ = QtWidgets.QFileDialog.getOpenFileName(
    None, "Select File", "", "Line Files (*.mcsv)")
if import_file_path == '':
    msgBox = QtWidgets.QMessageBox()
    msgBox.setText("No file selected")
    msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
    msgBox.setIcon(QtWidgets.QMessageBox.Warning)
    msgBox.exec_()


data = pd.read_csv(import_file_path)

df = pd.DataFrame(data, columns=['Easting', 'Northing'])
df.drop(df.tail(1).index, inplace=True)  # drop -9999 row
df['Easting'] = df['Easting'].astype("string")
df['Northing'] = df['Northing'].astype("string")


p = Polygon(list(zip(df["Easting"], df["Northing"])))

print(str(p))

The .mcsv looks like this:

Map,Name,Easting,Northing
1,1,416213.873,6507344.904
1,1,424283.100,6509982.331
1,1,428632.580,6496675.102
1,1,418176.907,6493257.665
1,1,415338.984,6501940.281
1,1,416213.873,6507344.904
-9999,-9999,-9999,-9999

and the SPYDER generated output looks like:

POLYGON ((416213.873 6507344.904, 424283.1 6509982.331, 428632.58 6496675.102, 418176.907 6493257.665, 415338.984 6501940.281, 416213.873 6507344.904))

And this is the QGIS error message it get:

exec(Path('C:/Users/client/AppData/Local/Temp/tmpq5jtxh23.py').read_text())
Traceback (most recent call last):
  File "C:\PROGRA~1\QGIS32~1.2\apps\Python39\lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "<string>", line 24, in <module>
  File "C:\PROGRA~1\QGIS32~1.2\apps\Python39\lib\site-packages\shapely\geometry\polygon.py", line 261, in __init__
    ret = geos_polygon_from_py(shell, holes)
  File "C:\PROGRA~1\QGIS32~1.2\apps\Python39\lib\site-packages\shapely\geometry\polygon.py", line 539, in geos_polygon_from_py
    ret = geos_linearring_from_py(shell)
  File "C:\PROGRA~1\QGIS32~1.2\apps\Python39\lib\site-packages\shapely\geometry\polygon.py", line 502, in geos_linearring_from_py
    lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
ctypes.ArgumentError: argument 4: <class 'TypeError'>: wrong type

QGIS 3.24.2 – Tisler Python version 3.9.5

Best Answer

You are converting your coordinates to "string" type:

df['Easting'] = df['Easting'].astype("string")
df['Northing'] = df['Northing'].astype("string")

and then making a polygon:

p = Polygon(list(zip(df["Easting"], df["Northing"])))

A simple test in Python (outside QGIS) gives me this:

>>> df = pd.DataFrame(dict(Easting=[1,2,3,4],Northing=[4,5,6,7]))
>>> df['Easting'] = df['Easting'].astype("string")
>>> df['Northing'] = df['Northing'].astype("string")
>>> p = Polygon(list(zip(df["Easting"], df["Northing"])))
Traceback (most recent call last):
  File "shapely/speedups/_speedups.pyx", line 252, in shapely.speedups._speedups.geos_linearring_from_py
AttributeError: 'list' object has no attribute '__array_interface__'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/rowlings/.local/lib/python3.8/site-packages/shapely/geometry/polygon.py", line 261, in __init__
    ret = geos_polygon_from_py(shell, holes)
  File "/home/rowlings/.local/lib/python3.8/site-packages/shapely/geometry/polygon.py", line 539, in geos_polygon_from_py
    ret = geos_linearring_from_py(shell)
  File "shapely/speedups/_speedups.pyx", line 373, in shapely.speedups._speedups.geos_linearring_from_py
TypeError: must be real number, not str

without the type conversion it works fine:

>>> df = pd.DataFrame(dict(Easting=[1,2,3,4],Northing=[4,5,6,7]))
>>> p = Polygon(list(zip(df["Easting"], df["Northing"])))
>>> 

I don't know why this works for you in Spyder, perhaps a different version of shapely that tolerates string inputs and does a conversion to numeric?

Related Question