Overpass color sets differently - openstreetmap

I was working on this problem where I have to create several sets of different regions, give these sets all different colors and show this on a map.
I've done this several years back by hand, in Photoshop, but when I had to do it again this year I was planning on automating it.
So, an example would be that the set of areas {"Rotterdam", "Vlaardingen"} will be coloured red; whereas the set of regions {"Den Haag", "Delft"} will be coloured blue.
I was planning on using the Overpass API for this. However, while I'm able to create one set of regions and color these, I cannot get multiple sets with different colors working. I would like to know if this even is possible, and if so, how I would do that. It seems like it should be possible, as it also is possible to have different colors for other selectors.
Coloring of one set:
(
rel[name="Rotterdam"];
rel[name="Vlaardingen"];
)->.myArea1;
rel.myArea1[admin_level=10][type=boundary][boundary=administrative];
out geom;
{{style:
relation
{ color:red; fill-color:red; }
}}
Now, the docs of Overpass state that you can use classes as selectors.
However, I have tried multiple ways to create classes, but the different sets either show up in the same colour, or in the default colour.
I've included some of my attempts below.
(Note; The solutions below do not work)
Tried solution 1:
(
rel[name="Rotterdam"];
rel[name="Vlaardingen"];
)->.myArea1;
(
rel[name="Delft"];
rel[name="Den Haag"];
)->.myArea2;
rel.myArea1[admin_level=10][type=boundary][boundary=administrative];
rel.myArea2[admin_level=10][type=boundary][boundary=administrative];
out geom;
{{style:
relation.myArea1
{ color:red; fill-color:red; }
relation.myArea2
{ color:blue; fill-color:blue; }
}}
Tried solution 2:
(
rel[name="Rotterdam"];
rel[name="Vlaardingen"];
)->.myArea1;
{{{set .myArea1;}}
(
rel[name="Delft"];
rel[name="Den Haag"];
)->.myArea2;
{{{set .myArea2;}}
rel.myArea1[admin_level=10][type=boundary][boundary=administrative];
rel.myArea2[admin_level=10][type=boundary][boundary=administrative];
out geom;
{{style:
relation.myArea1
{ color:red; fill-color:red; }
relation.myArea2
{ color:blue; fill-color:blue; }
}}
Tried Solution 3:
(
rel[name="Rotterdam"];
rel[name="Vlaardingen"];
)->.myArea1;
{{{set .myArea1;}}
(
rel[name="Delft"];
rel[name="Den Haag"];
)->.myArea2;
{{{set .myArea1;}}
(rel.myArea1[admin_level=10][type=boundary][boundary=administrative]; rel.myArea2[admin_level=10][type=boundary][boundary=administrative];) -> .comb;
.comb out geom;
{{style:
relation.myArea1
{ color:red; fill-color:red; }
relation.myArea2
{ color:blue; fill-color:blue; }
}}
Tried solution 4:
(
rel[name="Rotterdam"];
rel[name="Vlaardingen"];
)->.myArea1;
(
rel[name="Delft"];
rel[name="Den Haag"];
)->.myArea2;
rel.myArea1[admin_level=10][type=boundary][boundary=administrative];
{{style:
relation
{ color:red; fill-color:red; }
}}
out geom;
rel.myArea2[admin_level=10][type=boundary][boundary=administrative];
out geom;
{{style:
relation
{ color:blue; fill-color:blue; }
}}
If anyone could help me out here, that would be highly appreciated.
Kind Regards,
Toby

You cannot reuse the inputset assignment ")->.myArea1;" in the MapCSS section, as this part of the query is being executed by Overpass API (=the database backend), while MapCSS is executed solely in your browser (=frontend code).
As Overpass API doesn't return any indication as to which inputset a certain relation originates from, you cannot use the inputset name "myArea1" in a MapCSS expression.
Effectively, this means that every syntax variation you've tried is basically unsupported by the very way this query gets executed in the backend and rendered in your browser.
Unless you find some other way to group those relations by some other common tag, I'm afraid you would have to explicitly use the name=* tag for each relation.
rel[type=boundary]
[boundary=administrative]
[admin_level=10]
[name~"^(Rotterdam|Vlaardingen|Delft|Den Haag)$"];
out geom;
{{style:
relation[name=Rotterdam]
{ color:blue; fill-color:red; }
relation[name=Vlaardingen]
{ color:red; fill-color:red; }
relation[name=Delft]
{ color:red; fill-color:blue; }
relation[name=Den Haag]
{ color:red; fill-color:blue; }
}}
Try it in overpass turbo: https://overpass-turbo.eu/s/Hkh

Related

Why am I able to bypass pagination when I call the same field twice (with different queries) in GitHub's GraphQL API

I noticed something I don't understand while trying to get the number of open issues per repository for a user.
When I use the following query I am asked to perform pagination (as expected) -
query {
user(login:"armsp"){
repositories{
nodes{
name
issues(states: OPEN){
totalCount
}
}
}
}
}
The error message after running the above -
{
"data": {
"user": null
},
"errors": [
{
"type": "MISSING_PAGINATION_BOUNDARIES",
"path": [
"user",
"repositories"
],
"locations": [
{
"line": 54,
"column": 5
}
],
"message": "You must provide a `first` or `last` value to properly paginate the `repositories` connection."
}
]
}
However when I do the following I actually get all the results which doesn't make any sense to me -
query {
user(login:"armsp"){
repositories{
totalCount
}
repositories{
nodes{
name
issues(states: OPEN){
totalCount
}
}
}
}
}
Shouldn't I be asked for pagination in the second query too ?
TLDR; This appears to be a bug. There's no way to bypass the limit applied when fetching a list of resources.
Limiting responses like this is a common feature of public APIs -- if the response could include thousands or millions of results, it'll tie up a lot of server resources to fulfill it all at once. Allowing users to make those sort of queries is both costly and a potential security risk.
Github's intent appears to be to always limit the amount of results when fetching a list of resources. This isn't well documented on the GraphQL side, but matches the behavior of their REST API:
Requests that return multiple items will be paginated to 30 items by default. You can specify further pages with the ?page parameter. For some resources, you can also set a custom page size up to 100 with the ?per_page parameter.
For connections, it looks like the check for the first or last parameter is only ran whenever the nodes field is present in the selection set. This makes sense, since this is ultimately the field we want to limit -- requesting other fields like totalDiskUsage or totalDiskUsage, even without a limit argument, is harmless with the regard to above concerns.
Things get funky when you consider how GraphQL handles selection sets with selections that have the same name. Without getting into the nitty gritty details, GraphQL will let you request the same field multiple times. If the field in question has a selection set, it will effectively merge the selection sets into a single one. So
query {
user(login:"armsp") {
repositories {
totalCount
}
repositories {
totalDiskUsage
}
}
}
becomes and is equivalent to
query {
user(login:"armsp") {
repositories {
totalCount
totalDiskUsage
}
}
}
Side note: The above does not hold true if you explicitly give one of the fields an alias since then the two fields have different response names.
All that to say, technically this query:
query {
user(login:"armsp"){
repositories{
totalCount
}
repositories{
nodes{
name
issues(states: OPEN){
totalCount
}
}
}
}
}
should also blow up with the same MISSING_PAGINATION_BOUNDARIES error. The fact that it doesn't means the selection set merging is somehow borking the check that's in place. This is clearly a bug. However, even while this appears to "work", it still doesn't get around whatever limits Github has applies at the storage layer -- you will always get at most 100 results even when exploiting the above bug.

How to use subcriteria in populate (for example : .populate('something',{select:[]})) in sails js

.populate('something',{select:[]})) in sails js . for me its an ambiguous usage. Is there any alternate solution for the problem
I used select inside populate ... but it shows sub-criteria doesn't work in this version of sails
Banktransaction.find(newData).populate('project_id',{select:['project_name']}).exec((err,banktrans)=>{
if(err){
return res.json({
error : err
});
}
if(!banktrans){
return res.notFound();
}else{
return res.json({
'responseType':"success",
'responseMessage':"Banktransaction details founded successfully",
'result': banktrans
});
}
});
//result
{
"error": {
"name": "UsageError",
"code": "E_INVALID_POPULATES",
"details": "Could not populate `project_id` because of ambiguous usage. This is a singular (\"model\") association, which means it never refers to more than _one_ associated record. So passing in subcriteria (i.e. as the second argument to `.populate()`) is not supported for this association, since it generally wouldn't make any sense. But that's the trouble-- it looks like some sort of a subcriteria (or something) _was_ provided!\n(Note that subcriterias consisting ONLY of `omit` or `select` are a special case that _does_ make sense. This usage will be supported in a future version of Waterline.)\n\nHere's what was passed in:\n{ select: [ 'project_name' ] }"
}
}
You've probably figured it out by now, but .populate() is limited, and sometimes the documentation for sails is wrong. I wrote a helper specifically to populate based on 3rd-normal O2M/M2M association tables. My method also required model methods giving the basic config of each association's field name and a reference to its model class. It's NOT graceful, it's a separate query for each record, but perhaps some of the details of my approach may interest you:
My populate helper.
Example usage.

Grouped nodes in OpenStreetMap with Overpass API

Hy.I would like to query nodes gruped by some area. For example: how to get all nodes (e.g. peaks) for given area (eg. administrative boundary - country).
Something like join in SQL:
SELECT n.*, a.name from node n LEFT JOIN area a ON n.area_id = a.id WHERE n.type = "peak"
Resoult would be something like:
{ features: [
{
type: "node:",
area: "slovenia"
properties: {....},
geometry: {...}
},
...
]}
or maybe:
{ areas: [
slovenia: {
nodes: [
{
type: "node:",
area: "slovenia"
properties: {...},
geometry: {...}
},
...
]
},
...
]}
Is this even possible? Or should I first make 1 query for all areas and then for each area make another query?
Area in area support is not yet officially available (see this Github pull request for some ideas how this might look like in the future), but you could use the approach described on the following help page:
https://help.openstreetmap.org/questions/35976/add-reverse-geocoding-information-to-the-overpass-resulting-set
In particular I'd recommend to take a look at the following query: http://overpass-turbo.eu/s/4FJ
It works with a single query but mixes sign posts with all areas this sign post is included.You should be able to easily adjust this to your tags / area. Note that a bit of post processing on the result may be required.
Probably the closest thing you're looking for is also described in the Github pull request. This would print the area followed by all nodes in that area. But as I mentioned, this will only be available at some point in the future.
Sample output:
#oname #id name
area 3600062387 Landkreis Merzig-Wadern
node 313138635
node 313150002
node 313460474
node 315050154
node 431311279
...

Returning objects with multiple types in a RESTful way

I'm currently designing an API to handle requests from mobile clients. To achieve some degree of decoupling between backend and client I would like to define the webservices in a RESTful way. The challenge that I am facing is returning multiple objects with different types for a single call.
Lets say we have the following Model:
Harbour ... Top level entry
Boat shed ... Assigned to a specific harbour (0..n)
Boat ... Assigned to a specific boat shed (0..n), or directly to a harbour (0..n)
As far as i understand REST, if I now want to display all the boats and sheds in the harbour I would send two requests:
/harbours/{harbour_id}/boats Returning a list of all boats. Boats in a shed would contain an id linking to the shed they are in
/harbours/{harbour_id}/sheds Returning a list of all sheds
As I want to use the web service in a mobile scenario, it would be ideal to combine these two calls into one. This could then either return the list of boats with the shed object nested within, or both object types side by side:
/harbours/22/boats
[
{
"id":1,
"boatName":"Mary",
"boatShed":{
"id":1,
"shedName":"Dock 1",
"capacity":55
}
},
{
"id":2,
"boatName":"Jane",
"boatShed":{
"id":1,
"shedName":"Dock 1",
"capacity":55
}
}
]
or
/harbours/22/boats
{
"boats":[
{
"id":1,
"boatName":"Mary",
"boatShedId":1
},
{
"id":2,
"boatName":"Jane",
"boatShedId":1
}
],
"sheds":[
{
"id":1,
"shedName":"Dock 1",
"capacity":55
}
]
}
My question now is, which of these ways is closer to the idea behind REST, or is it not RESTful at all?
As #Tarken mentioned /boats request should not return sheds in the top level (since the url assumes you're asking for collection of resource Boat)
If you have relations defined as follows
Harbour:
boats: Boat[]
sheds: Shed[]
Shed:
boats: Boat[]
Boat:
harbour: Harbour
shed: Shed
/harbours/ID then returns a Harbour representation with boats and sheds relation set.
{
boats:
[
{ Boat },
{ Boat },
..
],
sheds:
[
{ Shed },
{ Shed },
..
],
...
}
Nothing is against restful principles here - the url uniquely identifies a resource and resource representation can be anything, with links to other resources as well.
Create a Harbour model which contains both Boat Shed and Boat information. If i am implementing the service in Java, then i would have done something like this :
class Boat{
...
}
class BoatShed{
...
}
class Harbour{
List<Boat> boats;
List<BoatShed> boatSheds;
...
}
You can create an API like /api/harbours/{harbourId}.
As per your question you want to display all the boats and sheds in the harbour, say id=1234, you can make a request like this :
GET /api/harbours/1234
This will return list of Boats and list of Boat Sheds like this:
{
"boats":[
{
"id":1,
"boatName":"Mary",
"boatShedId":1
},
{
"id":2,
"boatName":"Mary2",
"boatShedId":2
}
],
"sheds":[
{
"id":1,
"shedName":"Dock 1",
"capacity":55
},
{
"id":2,
"shedName":"Dock 2",
"capacity":50
}
]
}
EDIT
As you want to get boats and Sheds side by side by sending one request, the api/hourbours/{id} looks good according to REST API design principles.
Getting all sheds while requesting for boats is not in accordance with ideal REST API design, but if you want to achieve the same you can d the following.
If you want that way, then first one /api//harbours/{id}/boats looks good to me.

CodeMirror: How add tables to sql-hint?

I can't figure how add tables to codemirror. I have sql-hint.js included, and work for keywords but don't understand how add tables and columns...
Sadly, this does not appear to be documented anywhere.
With some trial and error I was able to figure out that you can pass in a structure of table and column names as options when invoking the hinter, like this:
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.sql, {
tables: {
"table1": [ "col_A", "col_B", "col_C" ],
"table2": [ "other_columns1", "other_columns2" ]
}
} );
}
I know that this question is somewhat old but..I found an interesting way, valid in 4.3 release (I don't know anything about older releases): Just add the "CodeMirror.hint.sql" value (without quotes, as its a function) as "hint" option and add the "tables" object as a sub-object defined in "hintOptions" object.
Something like:
CodeMirror.fromTextArea(document.getElementsByTagName("textarea")[0], {
mode: "text/x-sql",
extraKeys: {"Ctrl-Space": "autocomplete"}, // To invoke the auto complete
hint: CodeMirror.hint.sql,
hintOptions: {
tables: {
"table1": [ "col_A", "col_B", "col_C" ],
"table2": [ "other_columns1", "other_columns2" ]
}
}
});
That's it. Note that the "extraKeys" is absolutely not needed, but I found it to be great to test the autocomplete more easily. =)
Good luck. :)