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
-
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
-
-
@daveM Also, be careful, these geocode functions need an Internet connection and if you call them to often, you could be refused during some time...
-
you should not send more than one geocoding request per minute
Édit: typed before reading your post just under
-
Rofl re not speaking your age. Lol. I’ve just hit a milestone that involved the words [‘half’,’century’], but as with most people I know, now it is just a number. Nobody really cares (unless you’re looking for work or a partner!!!) lol
Re the geocode API, I’ve been wondering what the “go” is with it. I have been using the google API for a few years and never had any issues. But I’ve always respected the limits and played by the rules. I was surprised Apple has opened them up to third parties. I’ll dig through the Apple docs later and see what restrictions are in place, but I don’t plan to use it too often. I’m developing an in-house tool that will allow using it as required. But it’ll only be 10-20 times a day. Although I may hit limits in testing. I hope that’s not the case. Lol
-
-
I localize my contacts on a map using this CLGeocoder and I have more than 200 contacts. The script has to retry a lot because it is too much requests in some seconds.
On GitHub, this explanation of my code:
sometimes, geocodeAddressString returns None. Either the address string is invalid, but somerimes, a retry gives a correct gps localization. Perhaps due to a big number of calls in a short time. In this case, the script display a button 'nn not (yet) localized' and starts a thread which will retry (maximum 100 times) all not yet localized contacts. The delay between two retries increase at each retry. The button title is green if the thread runs and red if not. Tapping this button gives the list of these contacts with their retries number