0

I have a problem using lambda: ... in my program. As I don't want my TkInter GUI to execute the functions automatically, I am using lambda. Problem is though that for Button3 it makes my program crash and I have no idea why. Without lambda it works absolutely fine. Here is my code:

import ogr, osr, sys, os
import psycopg2
import ppygis
from datetime import datetime, date
import time
import re
from Tkinter import *
import tkFileDialog
from tkFileDialog import askopenfilename # Open dialog box
from tkMessageBox import showerror

class trip_calculator:

    def __init__(self):
        global root
        root = Tk()

        def open_file_dialog():
            returned_values = {} 
            returned_values['filename'] = askopenfilename()
            Label(root, text= returned_values.get('filename')[52:] + '     selected').grid(row=2)    

            filepath = returned_values.get('filename')

            #OPEN GPX DRIVER
            driver = ogr.GetDriverByName('GPX')
            datasource = driver.Open(filepath)

            if datasource is None:
                print 'not open'
            else:
                print 'open'

            #GEOMETRY
            datasource_layer = datasource.GetLayer(2)

            #GRAB TIMESTAMPS, ELEVATION, CADENCE ETC.
            datasource_layer2 = datasource.GetLayer(4)

            #GRAB GEOMETRY INFORMATION AND TRANSFORM TO UTM
            datasource_feature = datasource_layer.GetNextFeature()
            geoSR = osr.SpatialReference()
            geoSR.ImportFromEPSG(4326) 
            utmSR = osr.SpatialReference()
            utmSR.ImportFromEPSG(32633) 
            coordTrans = osr.CoordinateTransformation(geoSR, utmSR)
            geom = datasource_feature.GetGeometryRef()
            geom1 = geom.Simplify(0)
            geom.Transform(coordTrans)
            geom1.Transform(coordTrans)

            Label(root, text= 'geometries transformed successfully').grid(row=2, column=5)    
            #
            # This is where the crash of Python occurs, 
            # `lambda: calculation(...)` won't start. 
            # It crashes at `features = iter(datasource_layer2)`
            #
            self.button3 = Button(root, text='calculate attributes',   command=lambda:calculation(self,geom1,datasource_layer2)).grid(row=10, column=10, pady=10, padx=10)

        def quit_me():
            root.quit()


        def calculation(self, geom1, datasource_layer2):
        #NET AND GROSS TIME CALCULATION
            timestamps_net = []  
            timestamps_net_helper = []  
            timestamps_elapsed = []  
            elevation_helper = []
            print datasource_layer2
            features = iter(datasource_layer2)
            next(features)
            for feature in features:
                if len(timestamps_net_helper) == 2:
                    timestamps_net_helper = timestamps_net_helper[-1:] 
                timestamp = feature.GetField(4)
                elevation =  feature.GetField(3)
                elevation_helper.append(elevation)
                timestamp_stripped = timestamp[:-3]
                day = timestamp[:-11]
                #FOR GROSS CALCULATION 
                timestamps_elapsed.append(timestamp_stripped)
                #FOR NET CALCULATION
                timestamps_net_helper.append(timestamp_stripped)
                if len(timestamps_net_helper) == 2:
                    #CALCULATE SECONDS BETWEEN
                    time_a = datetime.strptime(timestamps_net_helper[0], "%Y/%m/%d %H:%M:%S") 
                    time_b = datetime.strptime(timestamps_net_helper[1], "%Y/%m/%d %H:%M:%S") 
                    time_difference = time.mktime(time_b.timetuple()) - time.mktime(time_a.timetuple())
                    #IF SECONDS LESS THAN 20 BETWEEN GPS TIMESTAMP THEN ADD UP NET TIME
                    if time_difference < 20:
                        timestamps_net.append(time_difference)
            seconds = sum(timestamps_net)
            hours = seconds/60/60
            time_length_net = time.strftime('%H:%M:%S', time.gmtime(seconds))

            #CLIMB.....
            positive_climb = []
            negative_climb = []
            for a, b in zip(elevation_helper, elevation_helper[1:]):
                if a > 0.0 and b > 0.0:
                    if b > a:
                        positive_climb.append(b-a)
                    elif b == a:
                        pass
                    else:
                        negative_climb.append(a-b)
            positive_climb = sum(positive_climb)
            negative_climb = sum(negative_climb)

            #GROSS (ELAPSED TIME)
            start = datetime.strptime(timestamps_elapsed[0], "%Y/%m/%d %H:%M:%S")  
            end = datetime.strptime(timestamps_elapsed[-1], "%Y/%m/%d %H:%M:%S")
            time_length = end - start

            #LENGTH
            length_km = float(geom1.Length()/1000)

            #AVERAGE SPEED
            avg_speed = (geom1.Length()/1000)/hours

            #CREATE LINESTRING FOR PPYGIS AND OGR LINESTRING
            myLine = ogr.Geometry(ogr.wkbLineString)
            polyline = []
            for z in range(geom1.GetPointCount()):
                x = geom1.GetX(z)
                y = geom1.GetY(z)
                myLine.AddPoint(x, y)
                point = ppygis.Point(x, y)
                polyline.append(point)
            myLine_ppy = ppygis.LineString(polyline)

            Label(root, text= time_length).grid(row=10, column=5)  
            Label(root, text= length_km).grid(row=11, column=5)  
            Label(root, text= avg_speed).grid(row=12, column=5)  



        self.button1 = Button(root, text='browse', command= open_file_dialog).grid(row=0,pady=10, padx=25)
        self.button2 = Button(root, text='close', command= quit_me).grid(row=3, pady=10, padx=25)


    root.mainloop()

trip_calculator()

The error occuring is libc++abi.dylib: pure virtual method called but only using lambda in the command of button3. Any ideas how to fix this?

5
  • 1
    calculation(...) has started to execute due to its use in the lambda expression. From what you said it sounds like the problem has something to do with the iter(datasource_layer2) call a several lines into the calculation() function. See if you can validate datasource_layer2 somehow as soon as you get it from calling datasource.GetLayer(4). Commented Oct 10, 2013 at 0:07
  • Hi Martineau, thanks for your answer. I'm pretty new to programming in general, would you have any suggestions on how to validate datasource_layer2 ? Cheers, Tim Commented Oct 10, 2013 at 7:20
  • 1
    Well, speaking very generally, since apparently it's supposed to support the iterator protocol, you could try something super simple like for feature in datasource_layer2: print feature and see if there are any problems. Also, if possible find the documentation on what kind of object it is and see what methods they're supposed to support or attribute they have and try call some of them or print some of them out. Commented Oct 10, 2013 at 7:34
  • Hey again martineau, I tried a normal for loop and it didn't work either. I now just took the part where the driver and datasource are selected and stuck them into the calculation(), it works now. Commented Oct 10, 2013 at 7:50
  • 1
    The problem could have something to do with the fact that datasource_layer2 is a local variable that no longer exists after the open_file_dialog() nested function returns. Same with geom1. You might be able to fix the problem by assigning them to self.datasource_layer2 and self.geom1 respectively so they last as long as the trip_calculator instance does. Commented Oct 10, 2013 at 8:09

1 Answer 1

2

The problem is likely due to the fact that some of the arguments you have in thelambdaexpression -- namelygeom1anddatasource_layer2-- are variables local to the nestedopen_file_dialog() function and don't exist later when the button is pressed and it has returned.

A simple fix would be to make them attributes of the trip_calculator instance, by adding a self.datasource_layer2 = datasource_layer2andself.geom1 = geom1 statements somewhere before the function returns (or just assigning them toselfand referencing them that way everywhere else).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.