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
-
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...
-
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.
-
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. -
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.
-
Of course the work around is to gather the data before calling Scene.run()
-
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!
-
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.
-
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 screenIn 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 locationfrom 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!
-
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.
-
@daveM could you post the code?
-
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()
-
@daveM For info and if needed, you can post a .pyui file by
- renaming to .txt
- edit
- select all
-copy - paste in the forum
-
Ahh cool Thanks.
-
@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
-
@daveM Tried on my iPhone with gps (I hope 😅) and same result
-
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
-
@daveM Just try working code on my iPad and ok (gps known via WiFi router even if no iPad cellular)
-
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
-
@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
-
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