Output a nested relation's nodes while keeping tags in Overpass-api - openstreetmap

I'm trying to custom render some golf courses by hole. The goal is to show a vector image of each hole and it's associated features.
I'm able to recurse through a course's relation but I can't figure out how to keep both tags and node locations. I'd like to output something like this (maybe after some post processing):
{
hole: 1,
par: 4,
...,
teeboxes: [{id:"x",nodes:[{lat,lon},...]},...],
fairways: [{id:"x",nodes:[{lat,lon},...]},...],
green: [{id:"x",nodes:[{lat,lon},...]},...],
}
My query currently looks like this:
[out:json][timeout:5];
relation["name"="Davis Golf Course"];
way(r)["golf"="hole"];
foreach->.a(
.a out;
way(around.a:40.0)["golf"];
out;
)
This gets me all of the features in the right order but I only get node IDs without node coordinates. The following will just gave me all nodes from these features, but I don't know which they belong to.
[out:json][timeout:5];
relation["name"="Davis Golf Course"];
way(r)["golf"="hole"];
foreach->.a(
.a out;
way(around.a:40.0)["golf"];
>>;
out;
)
I'm rather new, so I might be out in left field here. Thanks for any help!
Course reference

I was able to successfully query what I wanted with this:
[out:json][timeout:5];
way(<golf_course>);map_to_area ->.golfcourse;
way["golf"="hole"](area.golfcourse)->.holes;
(
relation["golf"="fairway"](area.golfcourse);
way["golf"~"^(green|tee|water_hazard|bunker|fairway)"](area.golfcourse);
)->.features;
.holes out geom;
.features out geom;

Related

How can I obtain all of the street names under a polygon in Overpass?

I am new to overpass (after only discovering it last night). I have a polygon I drew on QGIS and I plan to obtain its coordinates (long, lat). I'd then like to use these coordinates in overpass to obtain all of the road names in that area. I found a query online that obtains all road names in a city:
[out:csv ("name")][timeout:2500];
{{geocodeArea:Roma}}->.searchArea;
(
way["highway"]["name"](area.searchArea);
);
for (t["name"])
{
make street name=_.val;
out;
}
How can I adjust the following query so that I can specify a polygon function instead of city/area name?. I'm mindful of the syntax:
(poly:"latitude_1 longitude_1 latitude_2 longitude_2 latitude_3 longitude_3 …");
I'm just not sure where it would go in the query. I tried a few times but I was receiving errors or just blank results. Hopefully if I see an example I should be able to carry out my task effectively.
After doing some research I found the answer. This would give me a list of road names:
[out:csv ("name")][timeout:2500];
way["highway"]["name"]
(poly:"51.5566 0.0763 51.5734 0.0724 51.5203 0.0293");
out tags;
And this would give me a map view:
way["highway"]["name"]
(poly:"51.5566 0.0763 51.5734 0.0724 51.5203 0.0293");
out geom;

osmnx boundaries and admin_level

I hope someone here can help me to retrieve the correct administration level(s) from OSM. I am using the following code, but admin_level seems to be ignored:
tags = {"boundary":"administrative","admin_level":"4" }
gdf =ox.geometries.geometries_from_bbox(51.5, 51.0, 11.7, 11.2, tags)
gdf.shape
The bounding box seems to be used as a polygon to create an intersection with all the boundaries in the OSM database, the first tag is working because only administrative boundaries are returned, but the filter on level is ignored (gdf["admin_level"].head() shows level 6).
I would like to understand what I am doing wrong, and how I can use this package better; it seems like a very useful library.
Thanks,
Gijs
Result using the bounding box:
OK, rereading the documentation again made me realize that osmnx is using [OR] statements and not [AND] statements as I was presuming; removing the boundary request from the query is indeed giving only admin_level:4 results.
tags (dict) – Dict of tags used for finding objects in the selected area. Results returned are the union, not the intersection of each individual tag.
Some additional code: https://i.stack.imgur.com/Fw840.png

Gremlin - how do you merge vertices to combine their properties without listing the properties explicitly?

Background: I'm trying to implement a time-series versioned DB using this approach, using gremlin (tinkerpop v3).
I want to get the latest state node (in red) for a given identity node (in blue) (linked by a 'state' edge which contains a timestamp range), but I want to return a single aggregated object which contains the id (cid) from the identity node and all the properties from the state node, but I don't want to have to list them explicitly.
(8640000000000000 is my way of indicating no 'to' date - i.e. the edge is current - slightly different from the image shown).
I've got this far:
:> g.V().hasLabel('product').
as('cid').
outE('state').
has('to', 8640000000000000).
inV().
as('name').
as('price').
select('cid', 'name','price').
by('cid').
by('name').
by('price')
=>{cid=1, name="Cheese", price=2.50}
=>{cid=2, name="Ham", price=5.00}
but as you can see I have to list out the properties of the 'state' node - in the example above the name and price properties of a product. But this will apply to any domain object so I don't want to have to list the properties all the time. I could run a query before this to get the properties but I don't think I should need to run 2 queries, and have the overhead of 2 round trips. I've looked at 'aggregate', 'union', 'fold' etc but nothing seems to do this.
Any ideas?
===================
Edit:
Based on Daniel's answer (which doesn't quite do what I want ATM) I'm going to use his example graph. In the 'modernGraph' people-create->software. If I run:
> g.V().hasLabel('person').valueMap()
==>[name:[marko], age:[29]]
==>[name:[vadas], age:[27]]
==>[name:[josh], age:[32]]
==>[name:[peter], age:[35]]
then the results are a list of entities's with the properties. What I want is, on the assumption that a person can only create one piece of software ever (although hopefully we will see how this could be opened up later for lists of software created), to include the created software 'language' property into the returned entity to get:
> <run some query here>
==>[name:[marko], age:[29], lang:[java]]
==>[name:[vadas], age:[27], lang:[java]]
==>[name:[josh], age:[32], lang:[java]]
==>[name:[peter], age:[35], lang:[java]]
At the moment the best suggestion so far comes up with the following:
> g.V().hasLabel('person').union(identity(), out("created")).valueMap().unfold().group().by {it.getKey()}.by {it.getValue()}
==>[name:[marko, lop, lop, lop, vadas, josh, ripple, peter], lang:[java, java, java, java], age:[29, 27, 32, 35]]
I hope that's clearer. If not please let me know.
Since you didn't provide I sample graph, I'll use TinkerPop's toy graph to show how it's done.
Assume you want to merge marko and lop:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V(1).valueMap()
==>[name:[marko],age:[29]]
gremlin> g.V(1).out("created").valueMap()
==>[name:[lop],lang:[java]]
Note, that there are two name properties and in theory you won't be able to predict which name makes it into your merged result; however that doesn't seem to be an issue in your graph.
Get the properties for both vertices:
gremlin> g.V(1).union(identity(), out("created")).valueMap()
==>[name:[marko],age:[29]]
==>[name:[lop],lang:[java]]
Merge them:
gremlin> g.V(1).union(identity(), out("created")).valueMap().
unfold().group().by(select(keys)).by(select(values))
==>[name:[lop],lang:[java],age:[29]]
UPDATE
Thank you for the added sample output. That makes it a lot easier to come up with a solution (although I think your output contains errors; vadas didn't create anything).
gremlin> g.V().hasLabel("person").
filter(outE("created")).map(
union(valueMap(),
outE("created").limit(1).inV().valueMap("lang")).
unfold().group().by {it.getKey()}.by {it.getValue()})
==>[name:[marko], lang:[java], age:[29]]
==>[name:[josh], lang:[java], age:[32]]
==>[name:[peter], lang:[java], age:[35]]
Merging edge and vertex properties using gremlin java DSL:
g.V().has('User', 'id', userDbId).outE(Edges.TWEETS)
.union(__.identity().valueMap(), __.inV().valueMap())
.unfold().group().by(__.select(Column.keys)).by(__.select(Column.values))
.map(v -> converter.toTweet((Map) v.get())).toList();
Thanks for the answer by Daniel Kuppitz and youhans it has given me a basic idea on the solution of the issue. But later I found out that the solution is not working for multiple rows. It is required to have local step for handling multiple rows. The modified gremlin query will look like:
g.V()
.local(
__.union(__.valueMap(), __.outE().inV().valueMap())
.unfold().group().by(__.select(Column.keys)).by(__.select(Column.values))
)
This will limit the scope of union and group by to a single row.
If you can work with custom DSL ,create custom DSL with java like this one.
public default GraphTraversal<S, LinkedHashMap> unpackMaps(){
GraphTraversal<S, LinkedHashMap> it = map(x -> {
LinkedHashMap mapSource = (LinkedHashMap) x.get();
LinkedHashMap mapDest = new LinkedHashMap();
mapSource.keySet().stream().forEach(key->{
Object obj = mapSource.get(key);
if (obj instanceof LinkedHashMap) {
LinkedHashMap childMap = (LinkedHashMap) obj;
childMap.keySet().iterator().forEachRemaining( key_child ->
mapDest.put(key_child,childMap.get(key_child)
));
} else
mapDest.put(key,obj);
});
return mapDest;
});
return it;
}
and use it freely like
g.V().as("s")
.valueMap().as("value_map_0")
.select("s").outE("INFO1").inV().valueMap().as("value_map_1")
.select("s").outE("INFO2").inV().valueMap().as("value_map_2")
.select("s").outE("INFO3").inV().valueMap().as("value_map_3")
.select("s").local(__.outE("INFO1").count()).as("value_1")
.select("s").outE("INFO1").inV().value("name").as("value_2")
.project("val_map1","val_map2","val_map3","val1","val2")
.by(__.select("value_map_1"))
.by(__.select("value_map_2"))
.by(__.select("value_1"))
.by(__.select("value_2"))
.unpackMaps()
results to rows with
map1_val1, map1_val2,.... ,map2_va1, map2_val2....,value1, value2
This can handle mix of values and valueMaps in a natural gremlin way.

InstantiationException when using traversedElement

I'm attempting to setup a Graph which allows a query to follow "Redirect" edges from one vertex to another.
Vertices can only have a single Redirect edge going out; however, there may be a chain of Redirects that occur before reaching the final destination.
I'm attempting to grab the final vertex using the traversedElement function; however, even when I strip my implementation down to a query as simple as
select traversedElement(-1) from (traverse out() from #15:2)
I'm receiving the following error:
java.lang.InstantiationException: com.orientechnologies.orient.core.sql.functions.coll.OSQLFunctionTraversedElement
I'm not sure what the best way to debug this one might be, the simplified query I'm attempting above appears to match the documentation faithfully (documentation example):
SELECT traversedElement(-1) FROM ( TRAVERSE out() from #34:3232 WHILE $depth <= 10 )
Any words of wisdom would be greatly appreciated, thanks!
There was an issue with traversedElement() on last release (fixed on 2.0.7-SNAPSHOT). However you can use traversedEdge() and traversedVertex() that works.

Prevent Overpass API from returning nodes and show ways only

I'm trying to get all roads around a certain point. I'm using the following query:
(
way
(around:300,50.7913547,-1.0944082)
["highway"~"^(primary|secondary|tertiary|residential)$"]
["crossing"!~"."]
["name"];
>;
);
out;
I added the crossing exclusion because it kept including "markers" for crossings, and I'm only interested in roads.
However it seems to be ignoring the crossing and still plotting markers on the map, rather than just showing road outlines. This can be seen here.
These "nodes" that I don't want have the tags:
crossing=zebra
highway=crossing
which should fail my regex query, but it doesn't.
How do I get it to just return road plot lines, and none of these nodes/markers?
Sorry if my terminology is all wrong, I'm very new to this
The filter criterion you tried to use would only apply to the way itself rather than the nodes. Usually, a way wouldn't have a crossing tag, so this filter didn't have much of an effect on the final result. By using >; all of the nodes tags would shown up in the final result again.
I removed >; in your query and replaced out; by out geom; to only output the node lat/lon position without any tags.
You can try this out using the following link (currently pointing to overpass turbo beta)
Link