0

this post is the sequel of this other post:

Can't write decimal data into shape (shp) attribute table with Python

In that post I tried to simplify the problem, but it was a mistake, because that didn't express my real problem. I'm Sorry.

The problem is that I have a code that creates a shapefile and it works, but when I use it in a simple pyQt4 application, the issue of the last post appears: it rounds down the values of the written fields (Lat and Lng).

This is the code WITH THE PROBLEM:

# -*- coding: utf-8 -*-
# Created: Fri Feb 12 18:05:01 2016
#      by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui
import osgeo.ogr as ogr
import osgeo.osr as osr
import os, sys

DriverExt = {'ESRI Shapefile':'.shp'}

# START OF QT PART

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

# THE MAIN WINDOW

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(150, 70)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))

        # THE BUTTON

        self.boton_procesar = QtGui.QPushButton(self.centralwidget)
        self.boton_procesar.setGeometry(QtCore.QRect(20, 10, 98, 27))
        self.boton_procesar.setObjectName(_fromUtf8("boton_procesar"))

        MainWindow.setCentralWidget(self.centralwidget)

        # THE ACTION: prueba

        self.retranslateUi(MainWindow)
        QtCore.QObject.connect(self.boton_procesar, QtCore.SIGNAL(_fromUtf8("clicked()")),prueba)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.boton_procesar.setText(_translate("MainWindow", "procesar", None))

# END OF QT PART

# THE FUNCTIONS

def crearShape(arch, lat, lng, theDvr):

    # obtiene el Driver
    driver = ogr.GetDriverByName(theDvr)

    # obtiene la extension de archivo para ese driver mediante el diccionario creado al ppio
    theExt = DriverExt[str(theDvr)]

    # crea el nuevo FN
    FN = arch+theExt

    # crea el DataSource
    if os.path.exists(FN):
        print "el archivo ya existe"
    else:       
        theShp = driver.CreateDataSource(FN)

        # crea el SRS
        theSR = osr.SpatialReference()
        theSR.ImportFromEPSG(4326)

        # crea el Layer a partir del DataSource
        if theShp is None:
            print 'No se puede crear el archivo'
            sys.exit(1)

        capa = theShp.CreateLayer(os.path.basename(FN), theSR, ogr.wkbPoint)

        # crea los campos para las coordenadas
        fldLat = ogr.FieldDefn("Lat", ogr.OFTReal)
        capa.CreateField(fldLat)

        fldLng = ogr.FieldDefn("Lng", ogr.OFTReal)
        capa.CreateField(fldLng)

        # obtiene el tipo de Layer
        featureDefn = capa.GetLayerDefn()

        # crea un feature a partir de la definicion de la capa
        feature = ogr.Feature(featureDefn)

        # escribe sobre los campos
        feature.SetField("Lat", float(lat))
        feature.SetField("Lng", float(lng))

        # crea un punto
        pto = ogr.Geometry(ogr.wkbPoint)
        pto.AddPoint(lng, lat)

        # agrega al pto
        feature.SetGeometry(pto)

        # agrega los nuevos features a la capa
        capa.CreateFeature(feature)

        # DESTRUYE!
        pto.Destroy()
        feature.Destroy()
        theShp.Destroy()

        # mje y salir
        print "Done"
        sys.exit()

def prueba():
    crearShape("prueba_QT", -72.123456, -42.123456, "ESRI Shapefile")   

# ANOTHER QT PART

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

# END OF QT PART

If I test this code with the one suggested by gene in the other post:

from osgeo import ogr
data_source = ogr.Open("prueba2.shp")
layer = data_source.GetLayer(0)
feature = layer.GetFeature(0)
print feature.ExportToJson()

I get:

{"geometry": {"type": "Point", "coordinates": [-42.123456, -72.123456]}, "type": "Feature", "properties": {"Lat": -72.0, "Lng": -42.0}, "id": 0}

And this is the code WITHOUT THE PROBLEM:

# -*- coding: utf-8 -*-
# Created: Fri Feb 12 18:05:01 2016
#      by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!

import osgeo.ogr as ogr
import osgeo.osr as osr
import os, sys

DriverExt = {'ESRI Shapefile':'.shp'}

# THE FUNCTIONS

def crearShape(arch, lat, lng, theDvr):

    # obtiene el Driver
    driver = ogr.GetDriverByName(theDvr)

    # obtiene la extension de archivo para ese driver mediante el diccionario creado al ppio
    theExt = DriverExt[str(theDvr)]

    # crea el nuevo FN
    FN = arch+theExt

    # crea el DataSource
    if os.path.exists(FN):
        print "el archivo ya existe"
    else:       
        theShp = driver.CreateDataSource(FN)

        # crea el SRS
        theSR = osr.SpatialReference()
        theSR.ImportFromEPSG(4326)

        # crea el Layer a partir del DataSource
        if theShp is None:
            print 'No se puede crear el archivo'
            sys.exit(1)

        capa = theShp.CreateLayer(os.path.basename(FN), theSR, ogr.wkbPoint)

        # crea los campos para las coordenadas
        fldLat = ogr.FieldDefn("Lat", ogr.OFTReal)
        capa.CreateField(fldLat)

        fldLng = ogr.FieldDefn("Lng", ogr.OFTReal)
        capa.CreateField(fldLng)

        # obtiene el tipo de Layer
        featureDefn = capa.GetLayerDefn()

        # crea un feature a partir de la definicion de la capa
        feature = ogr.Feature(featureDefn)

        # escribe sobre los campos
        feature.SetField("Lat", float(lat))
        feature.SetField("Lng", float(lng))

        # crea un punto
        pto = ogr.Geometry(ogr.wkbPoint)
        pto.AddPoint(lng, lat)

        # agrega al pto
        feature.SetGeometry(pto)

        # agrega los nuevos features a la capa
        capa.CreateFeature(feature)

        # DESTRUYE!
        pto.Destroy()
        feature.Destroy()
        theShp.Destroy()

        # mje y salir
        print "Done"
        sys.exit()

def prueba():
    crearShape("prueba_QT", -72.123456, -42.123456, "ESRI Shapefile")   

prueba()

if I test the code with exactly the same test code, I get:

{"geometry": {"type": "Point", "coordinates": [-42.123456, -72.123456]}, "type": "Feature", "properties": {"Lat": -72.123456, "Lng": -42.123456}, "id": 0}

and if I run a diff command to compare both set of files I get:

The binary files conQT/prueba_QT.dbf and sinQT/prueba_QT.dbf are different

Community
  • 1
  • 1
Rodrigo E. Principe
  • 1,281
  • 16
  • 26
  • 1
    Your example doesn't include any tests. Add some code which prints some output proving there's a difference between the two cases. I ran a diff against the two sets of files produced by your suggested methods, and all the files are all byte for byte identical. So I'm afraid you've given me no reason to believe your claims about rounding errors. – ekhumoro Feb 17 '16 at 02:02
  • there you go @ekhumoro – Rodrigo E. Principe Feb 17 '16 at 02:39
  • That is not a valid test of the example code. You claim that the `prueba()` function produces different results when run in a pyqt program, as opposed to being run on its own. Where is the evidence for that? – ekhumoro Feb 17 '16 at 04:36
  • The function crearShape() which is called by prueba() produces a file, not a text output, and that is why I have to read that file to give you the proof. If I take out the pyQt part from the code and call prueba(), the file is created and the test output is: {"geometry": {"type": "Point", "coordinates": [-42.123456, -72.123456]}, "type": "Feature", "properties": {"Lat": -72.123456, "Lng": -42.123456}, "id": 0} Do you get different results? – Rodrigo E. Principe Feb 17 '16 at 10:49
  • I already said in my first comment that I checked the two sets of files using diff, and they are byte for byte identical. There is no reason why the other code you posted should produce different results, and it doesn't - i.e. there is no rounding down, or any other kind of error. So it is not a valid test, as i said. – ekhumoro Feb 17 '16 at 18:57
  • Please read the SO guidance on how to create a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). You should probably also make it clear exactly **how** you are running the example code, and in what environment. – ekhumoro Feb 17 '16 at 19:12
  • may be this helps clarifying the problem: https://youtu.be/A6GiQyrVmWk – Rodrigo E. Principe Feb 18 '16 at 11:03
  • See my previous comment. I'm not going to click on some random link. If you have further information that can help clarify your problem, you should edit your question accordingly. – ekhumoro Feb 18 '16 at 20:14
  • I have given a "minimal, complete and verifiable example".. read the code: I pass Lat:-72.123456 and Lng: -42.123456. With that, I do 2 things: 1. create a point 'pto.AddPoint(lng, lat)' 2. write the OFTReal fields 'feature.SetField("Lat", float(lat))' I even make them float and as you can see when I read the file (last part of the post), the "coordinates" are OK but the field aren't. What do the field's values are in the shp you produced with my code @ekhumoro? Besides, SO allows me to give you a link for my exmaple, and I don't see why not see a video in youtube.. I hope others do. – Rodrigo E. Principe Feb 18 '16 at 22:33
  • I think the vital point you are missing is that you need to provide an example that **other people** can use to replicate the problem. You clearly haven't done that, which strongly suggests that the problem lies entirely at your end. That is, it is caused by the way you are running the example, or the environment you are running it in, or some other confounding variable that you so far haven't mentioned. (FWIW, the values I get are `{"Lat": -72.123456, "Lng": -42.123456}`). – ekhumoro Feb 18 '16 at 23:41
  • Well, that is something. So, you replicated the pyQt code, created the shapefile, tested it, and got that result. Obviously the problem is mine. I don't know then. OS: ubuntu 14.04 - python 2.7.6 - IDE: geany, what else? – Rodrigo E. Principe Feb 19 '16 at 03:29
  • Here is what I had to do to make the code in your question testable: (1) create two scripts, one with pyqt, one with no pyqt at all; (2) add the second chunk of code to the bottom of the `pruebar()` function; (3) make sure each script creates a separate group of files; (4) verify that the printed output is the same; (5) run a diff against the two directories of files to make sure they are identical. NB: both scripts should be run using the same python, and in a console (i.e. not via some intermediary program). – ekhumoro Feb 19 '16 at 03:52
  • First of all, thank you @ekhumoro for your time and concern. I have done the same steps (1,2,3,4 and 5) and 5 said that the .dbf file is different. I check the table of contents in QGIS. And also, I execute the code directly (not using geany). – Rodrigo E. Principe Feb 19 '16 at 04:11
  • To make sure we're on exactly the same page: what is the output of `diff -rs dirA dirB`, where `dirA dirB` is the two directories of files you created? And please update your question to show the two scripts you used for testing. – ekhumoro Feb 19 '16 at 05:06
  • @ekhumoro I copied and pasted both codes (with and without) and copied and pasted the results of the test code. I had to translate the result of the diff because it was in spanish, but that is what it said. You can cleary see the difference in: `"properties": {"Lat": -72.123456, "Lng": -42.123456}` – Rodrigo E. Principe Feb 20 '16 at 00:11
  • You are the only person who can debug this any further, because no one else can replicate the problem. The procedure for doing this is simple. You just need to move parts from the pyqt example to the working example, little by little, line by line, until you find the part that causes the rounding down problem. If you do things properly, you should end up with a *very short*, truly minimal test case that identifies exactly where the problem is. It should only take about 15-20 minutes of trial and error to do it. – ekhumoro Feb 20 '16 at 19:09

0 Answers0