Locations Plugin


#21

You don’t need to hardcode it, just set png as the fallback, e.g.: ext = ext || 'png'


(Angus McLeod) #22

As we’re talking about Leaflet options here, I don’t see how that would work, but happy to accept a PR; maybe I’m just being dense.

In other news, new topic label styles thanks to some good feedback from @ChrisBeach

02 PM


(Chris Beach) #23

That looks good @Angus - cheers.


(Chris Beach) #24

I’ve installed the plugin on my site and enabled for a category visible only to mods. It got very positive comments - great job @angus!

One bit of feedback: we’re a local forum for South East London, so all our event, shop etc listings will be within a small area. The current geocoded label shows the following:

It’s missing a house number. And also has far more fields than desired. Ideally would read “Chris, 99 Ebsworth Street, SE23 1JG” in our use case.

It would be great if the displayed geocoded fields were configurable.


#25

Often the address is quite long. Wouldn’t it make sense to display only part of it and the whole in the link title?
What to display depends on the target: maybe it’s the city, maybe it’s the beginning of the address. In any case, having long addresses push the map button all the way to the right feels a bit clumsy.


(Angus McLeod) #26

@ChrisBeach @hellekin The content and formatting of geocoded results is not necessarily straightforward. I think it will help if I explain the context and specifics of this issue, partly to get your thoughts once you have the relevant details, and partly to explain it for others who may want to use this plugin.

Different geocoding providers produce different content and formatting for locations. @ChrisBeach from your screenshot I’m guessing you’re using the default (‘nominatim’) which uses OpenStreetMap data. @hellekin I’m guessing that you are also using nominatim / OSM. OSM display_names are often long winded.

The challenge for a plugin like this is standardize, both in content and formatting, so that you don’t write a whole lot of provider-specific code, while also allowing for site-specific customization. You both don’t like long addresses, but other people may.

The data pipeline

Firstly, user entered data e.g. “10 Downing St London”, is (obviously) not the same as the geocoded result.

If geocoded with mapzen via the Geocoder gem, the result would be

{"lat":"51.503166","lon":"-0.126431","address":"10 Downing Street, London, England, United Kingdom","city":"London","state":"City of Westminster","postalcode":"","countrycode":"GBR"}

If geocoded via a direct request to mapzen, the result would be

{"type"=>"Feature", "geometry"=>{"type"=>"Point", "coordinates"=>[-0.126431, 51.503166]}, "properties"=>{"id"=>"polyline:3041183", "gid"=>"mixed:address:polyline:3041183", "layer"=>"address", "source"=>"mixed", "name"=>"10 Downing Street", "housenumber"=>"10", "street"=>"Downing Street", "confidence"=>0.8, "match_type"=>"interpolated", "accuracy"=>"point", "country"=>"United Kingdom", "country_gid"=>"whosonfirst:country:85633159", "country_a"=>"GBR", "macroregion"=>"England", "macroregion_gid"=>"whosonfirst:macroregion:404227469", "region"=>"City of Westminster", "region_gid"=>"whosonfirst:region:85684061", "locality"=>"London", "locality_gid"=>"whosonfirst:locality:101750367", "neighbourhood"=>"Whitehall", "neighbourhood_gid"=>"whosonfirst:neighbourhood:85793317", "label"=>"10 Downing Street, London, England, United Kingdom"}}

if geocoded with nominatim via the Geocoder gem, the result would be

{"lat":"51.50344025","lon":"-0.127708209585621","address":"10 Downing Street, 10, Downing Street, St. James's, Covent Garden, Westminster, London, Greater London, England, SW1A 2AA, United Kingdom","city":"London","state":"England","postalcode":"SW1A 2AA","countrycode":"gb"}

If geocoded via a direct request to nominatim, the result would be

{"place_id"=>"173381493", "licence"=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", "osm_type"=>"relation", "osm_id"=>"1879842", "boundingbox"=>["51.5032573", "51.5036483", "-0.1278356", "-0.1273038"], "lat"=>"51.50344025", "lon"=>"-0.127708209585621", "display_name"=>"10 Downing Street, 10, Downing Street, St. James's, Covent Garden, Westminster, London, Greater London, England, SW1A 2AA, United Kingdom", "class"=>"tourism", "type"=>"attraction", "importance"=>0.89147137691773, "icon"=>"https://nominatim.openstreetmap.org/images/mapicons/poi_point_of_interest.p.20.png", "address"=>{"attraction"=>"10 Downing Street", "house_number"=>"10", "road"=>"Downing Street", "neighbourhood"=>"St. James's", "suburb"=>"Covent Garden", "city"=>"London", "state_district"=>"Greater London", "state"=>"England", "postcode"=>"SW1A 2AA", "country"=>"United Kingdom", "country_code"=>"gb"}}

So you can see that the Geocoder gem is already doing a fair bit of work for us by standardizing the results of all the different providers it supports to the following properties

result.latitude - float
result.longitude - float
result.coordinates - array of the above two in the form of [lat,lon]
result.address - string
result.city - string
result.state - string
result.state_code - string
result.postal_code - string
result.country - string
result.country_code - string

The attribute this plugin currently uses for labels (in the composer and in topics) is address.

As you can see by comparing the Geocoder results for nominatim and mapzen, the content of these standard attributes can still be significantly different.

The address attribute for the mapzen result is

10 Downing Street, London, England, United Kingdom

The address attribute for the nominatim result is

10 Downing Street, 10, Downing Street, St. James's, Covent Garden, Westminster, London, Greater London, England, SW1A 2AA, United Kingdom

If there is a house number, it will be included in the address string. This OSM result has a house number (it is 10 Downing Street after all), however, you will find that OSM results often don’t include house numbers. There’s a OSM forum topic about this here. The beauty of OSM is that it is user-generated, so one option you have, if there is a relatively small set of addresses you’ll be using with this plugin, is to add the house numbers to OSM yourself! (see further).

If adding the house numbers to OSM is not an option for you and you really need house numbers in your results, then I suggest you use another geocoding provider. As mentioned in the OP, my favorite is Mapzen, partly because they often will include the house numbers.

The Solution(s)

As you may have gathered, one simple solution is just to switch providers. I would actually recommend this for both of your cases as the primary course of action. Unless of course you’re keen to get involved with OpenStreetMap and add some house numbers (which would be cool). Switching providers would improve, if not solve, your content and formatting issues. Try out a few different providers and see which one you like. They all have generous free tiers.

One way this could be handled internally is by developing some kind of string parsing for the address attribute. The problem with this though is that you would need to check it against multiple addresses for each of the supported providers, and even then it would be very fragile.

A better way to handle this in the plugin would be to develop an attribute map for the raw results of each provider so you could use the more specific attributes in a standard way.

For example, nominatim’s attribute map, nominatim.yml, would look something like this:

house_number: "address.house_number"
road: "address.road"
...

Whereas mapzen’s attribute map. mapzen.yml, would look something like this:

house_number: "properties.housenumber"
road: "properties.street"
...

I was actually starting to do this when developing this plugin, but decided to go with the simpler approach of using the address from the Geocoder result directly for v0.1.

I may well do the attribute mapping soon (unless I (we) come up with a better idea), which will allow the plugin to generate site-customizable address labels.


#27

Can you get what the user enters? That might be a better label, then use whatever GeoCoder is providing in the title.

Otherwise, yes, this is a tricky problem.


(Angus McLeod) #28

Yes, you could use the user input in the location label, and if you have geocoding turned off in this plugin (i.e. location geocoding is set to none) that is exactly what happens.

The problems, as I see them, with using user-generated labels for geocoded locations are:

  • You would need to split the ‘display name’ and the location for the user in the Add Location modal, to allow the user to enter a ‘display name’ separate from the geocoded result that they select. This would be confusing UX. I’m sure a significant minority of users would not understand what is going on and make a mistake.

  • There would no longer be a 1:1 relationship between the location that appeared on the map and the location in the address label. Some address labels would be 100% accurate, some would not. This is also poor UX as the user wouldn’t know what information to rely on.

I think the better solutions are:

  1. Getting the provider right for the use case; and

  2. Adding attribute mapping so that site-specific formatting for address labels can be added.


(Chris Beach) #29

Thanks very much for the detailed explanation. I see now that the solution will be non-trivial.

In an ideally-flexible solution, the Discourse-locations plugin would be aware of fields from each geo provider at the most granular level available for each provider. Then in plugin settings, the forum admin chooses which fields are displayed (the “field list”). A sensible default “field list” could be provided by discourse-locations for each provider.

This avoids having to create mappings to a “standard” set of fields, which will be prohibitively difficult given providers are combining multiple data into a single string in some cases.


#30

OTOH, you could use something like the ‘show email’ button used in
Discourse to track who’s looking at emails on user profiles, with a
’show address’ button that would take much less space that the variable
space used now. Or display the address in the title attribute of some
location icon. Or maybe simply place the ‘show map’ button before the
address. :slight_smile:


#31

I’ve started using this but wondering about which API has performed the best (and thoughts on Google’s API)?


(Алексей Копаев) #32

And how can I shorten the displayed name of the address?

And how can I shorten the displayed name of the address?
Leave only the name of the city and the street.
And where do you choose to display the name in Russian?


(Angus McLeod) #33

Please see this post:


(Алексей Копаев) #34

Is it possible to replace it with something simpler? for example, in the plugin settings?


#35

It’s Google. OpenStreetMap is made by the people for the people. Not for some obscure shareholders and to nourish some greedy AI… Or is it the contrary. Surely Google’s API is fine, but you gotta feed what you want to see growing.


(Angus McLeod) #36

On Google, see the OP.

As explained in the post I linked to, the best way to achieve this right now is to use a different geocoding provider. For example Mapzen.


(Richard - DiscourseHosting.com) #37

We are seeing some issues - when the geocoding provider cannot be reached, Unicorn crashes upon restart. There is no rescue block around that code (actually it’s already in a rescue block). Don’t know why it is timing out by the way.

/var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/base.rb:288:in `rescue in make_api_request': Geocoder::LookupTimeout (Geocoder::LookupTimeout)
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/base.rb:274:in `make_api_request'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/base.rb:226:in `fetch_raw_data'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/base.rb:177:in `fetch_data'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/nominatim.rb:24:in `results'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/lookups/base.rb:47:in `search'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder/query.rb:11:in `execute'
        from /var/www/discourse/plugins/discourse-locations/gems/2.3.1/gems/geocoder-1.4.4/lib/geocoder.rb:22:in `search'
        from /var/www/discourse/plugins/discourse-locations/lib/geocode.rb:24:in `perform'
        from /var/www/discourse/plugins/discourse-locations/lib/geocode.rb:20:in `set_provider'
        from /var/www/discourse/plugins/discourse-locations/plugin.rb:88:in `rescue in block in activate!'
        from /var/www/discourse/plugins/discourse-locations/plugin.rb:84:in `block in activate!'

(Sam Saffron) #38

Great catch, I would strongly recommend not depending on outgoing network for boot (and not doing this in synchronous boot process) @angus and taking care of this stuff in a deferred task of sorts that can recover.


(Angus McLeod) #39

@RGJ @sam Thanks guys :+1:

Errors are first handled within the Geocoder gem itself (docs).

I’ve passed all errors thrown by the Geocoder gem through to the plugin and rescued them individually so as to give specific messages for each.

socket: "Your request failed. Please check your internet connection. If the problem persists, contact your site administrator."
timeout: "Your request timed out. Please wait 5 seconds and try again. If the problem persists, contact your site administrator."
request_denied: "Your request was denied. If the problem persists, contact your site administrator."
request_invalid: "Your request was invalid. If the problem persists, contact your site administrator."
query_limit: "Geocoding provider query limit reached. Please contact your site administrator."
api_key: "Geocoding provider api key invalid. Please contact your site administrator."
service_unavailable: "Geocoding provider service unavailable. Please contact your site administrator."

These will be displayed in the add-location modal.

The specific errors won’t display if they occur while you’re updating settings in site settings, as I have less control over those messages, however the generic update error will display.

@sam In terms of making this a deferred task, this is a search that is performed on an autocomplete in a modal, is it appropriate to use a background job in this scenario? It may also be relevant that:

edit @RGJ I should add that it is possible to set the timeout for the Geocoder plugin with the location_geocoding_timeout setting. If you find it’s timing out frequently, try increasing this.


(Stephan Eich) #40

Wow, what an extension.
Is it impossible to import kmz or kml files for locations?
This wil be a big feature, as single import, better for a mass import?
Hope for an answer.
Stephan from Berlin Germany.