omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Unable to use location.reverse_geocode inside a scene/layer

    Pythonista
    5
    27
    14319
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • lenoirmind
      lenoirmind last edited by

      Hello all,

      First of: what an inspiring app Pythonista is! I am a developer, though Python is pretty new to me. But I am a quick learner and start to really enjoy Python.

      I run into a strange problem and I do not really understand what I am doing wrong or what might go wrong.

      I've succesfully made simple sketching application based on the scene module elaborating on the 'example with layers'

      I've also succeeded in using the location module and retrieve my current location and made pythonista show me the address of my current location in the console.

      But when I try to use the same location code to retrieve and display my current addres in the scene mode, in either the console (displayed after closing the scene) or using the text() command in the scene, I only get 'none' as a result. Retrieving the gps coordinated does work from within a scene. But location.reverse_gecode does not.

      Did anyone run into this as well?

      Thanks in advance for the time and effort helping me out here...

      1 Reply Last reply Reply Quote 0
      • ccc
        ccc last edited by

        I saw the same behavior as you. In a scene, loc = location.get_location() works as expected but location.reverse_geocode(loc) always returns None.

        1 Reply Last reply Reply Quote 0
        • lenoirmind
          lenoirmind last edited by

          that, in a way is good news.
          I would be glad to help out here, but my knowledge about Python is not sufficient yet.
          Something with assignment and retrieval of global variables and class and/or function scopes within the scene module?
          I've had similar problems in php/java based systems when juggling with packages and static (global) variables and static class variables.

          1 Reply Last reply Reply Quote 0
          • dgelessus
            dgelessus last edited by

            I can confirm this as well. In a simple Python script all location functionality works as expected, but when called from inside a Scene neither geocode() nor reverse_geocode() work and return None. Wrapping the geocode call in a global function or separate module also doesn't appear to help.

            1 Reply Last reply Reply Quote 0
            • ccc
              ccc last edited by

              Of course the work around is to gather the data before calling Scene.run()

              1 Reply Last reply Reply Quote 0
              • lenoirmind
                lenoirmind last edited by

                Thanks for your time, both dgelessus snd ccc

                Agree.

                Location.geocode seems to work perfectly within a scene running. at least in my app. Only problem might be if you'd want to display the changing address in the scene while walking around using location.reverse_geocode.

                but there may be workarounds for that as well - different rev_gecode services?

                anyway... in my view this is exactly why i really like pythonista!

                1 Reply Last reply Reply Quote 0
                • dgelessus
                  dgelessus last edited by

                  Interesting, for me location.geocode() also doesn't work in a scene. I'm using the example address dict from the location module docs, which geocodes fine in a regular script.

                  Regarding a workaround, is there a way to softly stop scene running/rendering and execute code outside the scene class again? So far I couldn't find any way to do that without terminating the entire program. If this is possible, the scene could simply be stopped and the location reverse-geocoded and stored in a global variable, which could then be read inside the scene again. Of course this wouldn't be very clean and would probably also reset parts of the scene, but it might work.

                  For comparison, here's the test program that I've been using: http://pastebin.com/ZAWiaGGm

                  Blue "button" prints location to console, green one attempts to reverse-geocode an address, yellow one attempts to geocode the test address. The coding probably isn't too great, there may be some leftovers from failed workarounds, I don't have much experience with the scene module yet and I only recently got back into Python. It works as a simple test though.

                  1 Reply Last reply Reply Quote 0
                  • lenoirmind
                    lenoirmind last edited by

                    Thanks to your script example I found a strange anomaly, dgelessus!
                    It took my quite a while to figure this out and it is due to similar strange behavior I've seen wehen working in a PHP based project, where I found out that the contents of variables seemed to be updated in a different fashion when FIRST printing the values of these variables to stdout and THEN access the values of these variables to print them elsewhere - eg on a screen

                    In your code example at http://pastebin.com/ZAWiaGGm you've used this construction:

                     location.start_updates()
                                self.loc = location.get_location()
                                print(self.loc)
                                location.stop_updates()
                    

                    I've modified your code so the draw() method displays the value of the self.loc variable on the canvas as well as in the interpreter. As you've noticed, the interpreter's values are correctly updated. The values within the scene are not.

                    After some experimentation I've noticed the "print(self.loc))" line in your code and I got this "PHP problem hunch". I've added the same print() line in my Scenes based script and lo and behold! The location values are now correctly updated within the Scene's draw loop!

                    With your original script with the three buttons you can see the same behavior. If you comment out the 'print(self.loc)' line, you'll notice the values printed on the screen canvas are not updated. As soon as you uncomment the print() line, the values are correctly updated.

                    I've added my modifications here:

                    import console
                    import location

                    from scene import *

                    running = True
                    testaddr = {'Street': 'Infinite Loop', 'City': 'Cupertino', 'Country': 'USA'}
                    testcoords = (())

                    def geocode():
                    testcoords = location.geocode(testaddr)

                    class MainScene (Scene):
                    def init(self):
                    self.btn = 0
                    self.loc = ''

                    def setup(self):
                    	# This will be called before the first frame is drawn.
                    	pass
                    
                    def draw(self):
                    	# This will be called for every frame (typically 60 times per second).
                    	background(0, 0, 0)
                    	
                    	# draw wannabe buttons
                    	fill(0, 0, 1)
                    	rect(0, 0, 200, 200)
                    
                                # add continuous polling of location. Not so economic, but only for this testing case
                    	location.start_updates()
                    	self.loc = location.get_location()
                    
                                # make sure to add this print statement: comment this line to see the update of the self.loc value fail.
                    	print(self.loc)
                    	location.stop_updates()
                    
                                # if we've successfully obtained our location, display it in the scene in all it's floating number glory
                    	if self.loc:
                    		mylocation = '%.9f, %.9f, %d' % (self.loc['longitude'], self.loc['latitude'], self.loc['timestamp'])
                    		stroke(1,1,1)
                    		text(mylocation, 'Helvetica', 20, 100, 10, 6)
                    		
                    	# Draw a red circle for every finger that touches the screen:
                    	fill(1, 0, 0)
                    	for touch in self.touches.values():
                    		ellipse(touch.location.x - 50, touch.location.y - 50, 100, 100)
                    
                    def touch_began(self, touch):
                    	# determines touched "button"
                    	if touch.location.x < 200:
                    		if touch.location.y < 200:
                    			self.btn = 1
                    		elif touch.location.y < 400:
                    			self.btn = 2
                    		elif touch.location.y < 600:
                    			self.btn = 3
                    
                    def touch_moved(self, touch):
                    	pass
                    
                    def touch_ended(self, touch):
                    	stroke(1,1,1)
                    	# runs the tapped button's corresponding function
                    	if self.btn == 1:
                    		text('button 1', 'Helvetica', 20, 100, 200, 6)
                    		self.dumploc()
                            elif self.btn == 2:
                    		text('button 2', 'Helvetica', 20, 100, 300, 6)
                    		self.dumpaddr()
                    	elif self.btn == 3:
                    		text('button 3', 'Helvetica', 20, 100, 400, 6)
                    		self.geocode()
                    	self.btn = 0
                    
                    def dumploc(self):
                    	location.start_updates()
                    	self.loc = location.get_location()
                    	print(self.loc)
                    	location.stop_updates()
                    
                    def dumpaddr(self):
                    	self.addr = location.reverse_geocode(self.loc)
                    	print(self.addr)
                    
                    def geocode(self):
                    	geocode()
                    	print(testcoords)
                    

                    run(MainScene())

                    Though this perhaps doesn't solve the reverse_geocode issue, it does solve continuous update issue I've ran into.

                    Not sure I understand why this happens, but I am happy that I found a workaround for the continuous location update issue. If I find a gap in my schedule I will dive into the reverse_geocode issue.

                    Thanks for your input!

                    1 Reply Last reply Reply Quote 0
                    • daveM
                      daveM last edited by

                      I’ve stumbled across this problem tonight except it’s just a custom ui.View class and I’m trying to get a new geolocation and reverse location in the view’s update method. The generic lay/long speed and everything else is there, but the geolocation and reverse lookup keep returning None.

                      The script works perfectly outside a class.

                      I’m open to ideas because I’ve been scratching my head for hours.

                      cvp 1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp @daveM last edited by

                        @daveM could you post the code?

                        1 Reply Last reply Reply Quote 0
                        • daveM
                          daveM last edited by

                          working code

                          import console, ui, motion, time
                          import location
                          
                          start = time.time()
                          motion.start_updates()
                          location.start_updates()
                          
                          console.set_idle_timer_disabled(True)
                          
                          def dict_print(dic):
                          	l = 0
                          	for k in dic:
                          		l = max(l,len(k))
                          	for k,v in dic.items():
                          		print(f'{k}:'.ljust(l+1),v)
                          
                          for _ in range(1):
                          	
                          	my_location = location.get_location()
                          	print('location:')
                          	dict_print(my_location)
                          	
                          	
                          	#address_dict = {'Street': 'Infinite Loop', 'City': 'Cupertino', 'Country': 'USA'}
                          	
                          	my_address = {
                          		k:v for k, v in my_location.items()} 
                          	# if k=='latitude' or k=='longitude'}
                          	
                          	
                          	print ('my address1:')
                          	dict_print(my_address)
                          	my_address = location.geocode(my_location)
                          	print ('\nmy address2:')
                          	dict_print(dict(my_address))
                          	
                          	results = location.reverse_geocode(my_location)
                          	print ('reverse geocode:')
                          	if results:
                          		dict_print(results[0])
                          	print('authorised:',location.is_authorized())
                          	
                          	while False:
                          		a, b, c = motion.get_attitude()
                          		# a tilt left right
                          		# b roll forwards and backwards
                          		# c twist about horizontal axis
                          		print('{: .2f}, {: .2f}, {: .2f},'.format(a,b,c))
                          		time.sleep(.5)
                          	
                          motion.stop_updates()
                          location.stop_updates()```
                          
                          
                          # The non working code: 
                          *you will need to create a pyui file that contains three labels:*
                          ['latlong', 'speed', 'address']
                          
                           ```   import console, ui, time
                              import location, motion
                          
                              #console.set_idle_timer_disabled(True)
                          
                              def dict_print(dic):
                          	    l = 0
                          	    for k in dic:
                          	    	l = max(l,len(k))
                          	    s = ''
                          	    for k,v in dic.items():
                          		    s += f'{k.ljust(l+1)}: {v}\n'
                          	    return s 
                          		
                              class myview (ui.View):
                          	    pass
                          	    def __init__(self, *arg, **args):
                          		    start = time.time()
                          		    motion.start_updates()
                          		    location.start_updates()
                          	
                          	    def update(self):
                          	    	if not location.is_authorized():
                          			    self['address'].text = 'This app needs access to your location data'
                          			    return
                          		    my_location = location.get_location()
                          		    self['latlong'].text = ', '.join([str(my_location['latitude']), str(my_location['longitude'])])
                          		
                          		    self['speed'].text = ' / '.join(['{: .2} m/s'.format(my_location['speed']),'{: 0.2} km/h'.format(my_location['speed']*60*60/1000)])
                          	
                          		    results = location.geocode(my_location)
                          		    print(results)
                          		    results = location.reverse_geocode(my_location)
                          		    print ('reverse geocode:')
                          		    s=''
                          		    if results:
                          			    self['address'].text = dict_print(results[0])
                          		    #self['address'].text = str(results)
                          		    print(results)
                          		
                              location.start_updates()
                              motion.start_updates()
                              v = ui.load_view()
                              v.update_interval=1
                              print('authorised:',location.is_authorized())
                              v.present('sheet')
                              motion.stop_updates()
                              location.stop_updates()
                          
                          cvp 1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp @daveM last edited by

                            @daveM For info and if needed, you can post a .pyui file by

                            • renaming to .txt
                            • edit
                            • select all
                              -copy
                            • paste in the forum
                            1 Reply Last reply Reply Quote 0
                            • daveM
                              daveM last edited by

                              Ahh cool Thanks.

                              cvp 2 Replies Last reply Reply Quote 0
                              • cvp
                                cvp @daveM last edited by

                                @daveM I've tri d your program on my iPad WiFi (no gps) and my_location contains latitude and longitude but no address. Thus it is normal that geocode does not work but reverse should work, you're right

                                1 Reply Last reply Reply Quote 0
                                • cvp
                                  cvp @daveM last edited by

                                  @daveM Tried on my iPhone with gps (I hope 😅) and same result

                                  daveM 1 Reply Last reply Reply Quote 0
                                  • daveM
                                    daveM last edited by

                                    Yeah, I’m really not sure what’s happening. I don’t really get it. If you try the code at the very top, it should work as expected and GeoCode and ReverseGeo both work (probably not on your iPad, did you try the working code on your phone?

                                    I only dig up this old thread because the problem seemed to be identical and was hopeful that one of the original posters might remember how (if) they resolved it

                                    cvp 1 Reply Last reply Reply Quote 0
                                    • cvp
                                      cvp @daveM last edited by

                                      @daveM Just try working code on my iPad and ok (gps known via WiFi router even if no iPad cellular)

                                      1 Reply Last reply Reply Quote 0
                                      • daveM
                                        daveM @cvp last edited by

                                        @cvp

                                        Ahh found the issue. I didn’t look hard enough. There was another post detailing the answer and it has worked. Placing the first line here before the update gets things working!!

                                        @ui.in_background
                                        def update(self):
                                            If not...
                                        

                                        https://forum.omz-software.com/topic/5430/reverse-geolocation-works-on-console-but-not-in-code/5

                                        cvp 1 Reply Last reply Reply Quote 0
                                        • cvp
                                          cvp @daveM last edited by cvp

                                          @daveM well done
                                          the worst is that I knew it, I had read this topic, but I forgot, sad to grow old 👴🏻😢

                                          Only 3 months later, shame on me

                                          1 Reply Last reply Reply Quote 0
                                          • daveM
                                            daveM last edited by

                                            Lol. Yes. I saw your name there. All good. I’m not sure how much older than me you might be, but I certainly understand the pains of a failing memory!!! Lol

                                            cvp 3 Replies Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors