├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── new-query.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── background.md ├── colophon.md ├── contribute.md ├── for-local-mappers ├── benches.osm ├── disused-places.osm ├── high-street-recent-changes.osm ├── mismatched-streets.osm ├── overview.md ├── package.json ├── quite-interesting-no-link.osm └── the-high-street.osm ├── licence.md ├── map-css ├── brondby.osm ├── lotus-bahai-temple.osm ├── overview.md ├── package.json ├── styling-nodes.osm ├── the-bath-key.osm ├── ways-as-areas.osm └── ways-as-lines.osm ├── misc ├── all-the-things.osm ├── export-statues.osm ├── geocode-area.osm ├── grindelwald-glacier.osm ├── overview.md ├── package.json ├── playgrounds-with-styles.osm └── playgrounds.osm ├── overview.md ├── package.json ├── syntax-reference.md └── tutorial ├── 00-node-1.osm ├── 01-nodes.osm ├── 02-node-output.osm ├── 03-nodes-basic-filter.osm ├── 04-nodes-has-kv.osm ├── 05-nodes-combined-filter.osm ├── 06-nodes-union.osm ├── 07-nodes-differences.osm ├── 08-nodes-json-output.osm ├── 09-nodes-csv-output.osm ├── 10-the-default-set.osm ├── 11-query-a-set.osm ├── 12-radius-search.osm ├── 13-around-with-set.osm ├── 14-searching-by-polygon.osm ├── 15-ways.osm ├── 16-ways-and-their-nodes.osm ├── 17-ways-and-their-tags.osm ├── 18-nodes-and-ways.osm ├── 19-find-ways-from-nodes.osm ├── 20-relations.osm ├── 21-type-agnostic-queries.osm ├── 22-areas.osm ├── 23-areas-from-features.osm ├── 24-mapToArea.osm ├── 25-areas-via-nominatim.osm ├── 26-timeouts-and-endpoints.osm ├── overview.md └── package.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-query.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New query 3 | about: Submit a new query to the site 4 | title: '' 5 | labels: contribution 6 | assignees: '' 7 | 8 | --- 9 | 10 | To help get the query onto the website, please provide the following information. 11 | 12 | # Collection 13 | Which collection would you like this added to? See the list on the website, or just indicate whether this might be a new collection. 14 | 15 | # Title 16 | A short, descriptive title for the query. This is used in links to the query, so keep it short 17 | 18 | # Description 19 | A few sentences, or a few short paragraphs about what the query does. Maybe include details about how it works or how to customise it? 20 | 21 | # Query 22 | The actual Overpass QL query. Please test queries before submitting to ensure they work. 23 | 24 | # Links 25 | Include any useful links, e.g. to the OSM wiki, to help people understand what tags the query uses or provide some background about how it works. 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | By submitting content or updates then you'll be agreeing that your work can be 2 | put into the public domain in accordance with the CC0 waiver associated with this 3 | github repository. 4 | 5 | For [more information about contributing](http://osm-queries.ldodds.com/contribute.html) 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project contains both the source for the [OSM Queries website](https://osm-queries.ldodds.com) and the 2 | HTML which is served via github pages. 3 | 4 | Each of the project directories contains a collection of Overpass QL queries 5 | saved with the `.osm` file extension. 6 | 7 | The content is generated using the [Overpass Doc](https://github.com/ldodds/overpass-doc) tool. 8 | This converts a directory of query and markdown files to generate a simple website. 9 | 10 | If you're like to help out then here's [how to contribute](https://osm-queries.ldodds.com/contribute.html). 11 | -------------------------------------------------------------------------------- /background.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | The [Overpass API](https://wiki.openstreetmap.org/wiki/Overpass_API#Public_Overpass_API_instances) is a 4 | completely public API and can be freely used without registration. 5 | 6 | The API uses a custom query language called [Overpass QL](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL) 7 | that can be used to construct some very powerful and flexible queries. 8 | 9 | These are frequently written and executed via a web based API called [Overpass 10 | Turbo](https://wiki.openstreetmap.org/wiki/Overpass_turbo) which provides a wizard to support 11 | creation of queries, as well as some additional functionality. This includes providing the ability to save queries in your browser and view 12 | styled results on an embedded map. 13 | 14 | Like any powerful query language, Overpass QL has a lot of features. It also has syntax shortcuts that allow 15 | the same query to be expressed in different ways. 16 | 17 | It's really a simple programming language that has been designed to interact with 18 | the OpenStreetmap data model. This means it doesn't look like other query languages you may have used like SQL, GraphQL or SPARQL. 19 | 20 | This flexibility, complexity, and the variety of ways in which data can be 21 | tagged in OpenStreetmap, can make Overpass QL a bit daunting to learn. And tricky to 22 | use to get exactly the data you want. 23 | 24 | But it is a very powerful language and is well suited to: 25 | 26 | * running quick interactive explorations of OpenStreetmap data 27 | * extracting small exports of data to use in other analysis tools 28 | * integrating into simple scripts or applications that need to query the OSM database 29 | 30 | This website aims to do several things: 31 | 32 | * provide a range of useful queries that support people in making the most of the OSM data 33 | * add to the range of learning materials for Overpass QL 34 | * encourage the community to share useful queries, tips and tricks for making the most of the API 35 | 36 | These goals means its intended to complement a number of other existing resources, including: 37 | 38 | * [The Overpass Language Guide](https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide) which provides a 39 | detailed overview of the language syntax and functionality 40 | * The [Overpass API by example](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_API_by_Example) page on the OSM wiki which includes a range of examples 41 | * And the [Overpass API user's manual](https://dev.overpass-api.de/overpass-doc/en/) which is still a work in progress 42 | 43 | If you need more detail, then you're encouraged to explore these resources as well. 44 | -------------------------------------------------------------------------------- /colophon.md: -------------------------------------------------------------------------------- 1 | # Colophon 2 | 3 | This website was developed by [Leigh Dodds](http://ldodds.com). 4 | 5 | It was generated using an open source tool called [overpass-doc](https://github.com/ldodds/overpass-doc) 6 | which is designed to support the publication of collections of OverpassQL queries. It provides a 7 | simple command-line interface for generating documentation from packages of Overpass queries. 8 | 9 | The [source files are all in github](https://github.com/ldodds/osm-queries) and are in the public domain. 10 | 11 | It relies on [Bootstrap](https://getbootstrap.com/), [JQuery](https://jquery.com/) and 12 | [CodeMirror](https://codemirror.net/). 13 | 14 | The syntax highlighting code was adapted from the [Overpass Turbo code](https://github.com/tyrasd/overpass-turbo) 15 | which is published under an MIT Licence. 16 | 17 | The site is hosted and served from [Github Pages](https://pages.github.com/), with 18 | a [Lets Encrypt](https://letsencrypt.org/) certificate. 19 | -------------------------------------------------------------------------------- /contribute.md: -------------------------------------------------------------------------------- 1 | # How to contribute to this website 2 | 3 | If you would like to contribute to this website, then you can submit new 4 | example queries, corrections or improvements via [the github project](https://github.com/ldodds/osm-queries) 5 | 6 | By submitting content or updates then you'll be agreeing that your work can be 7 | put into the public domain in accordance with [the licence](licence.html) for 8 | the website and source 9 | 10 | The following sections have more information about how to contribute. But if you'd 11 | like to discuss the project or provide more general feedback then you can use the 12 | [discussion forum on github](https://github.com/ldodds/osm-queries/discussions) 13 | 14 | ## Submitting a new query or collection of queries 15 | 16 | If you'd like to submit a new query, then please either: 17 | 18 | * [file an issue](https://github.com/ldodds/osm-queries/issues) containing the proposed query, including a description of what it does 19 | * submit a pull request containing your proposed additions (or changes) 20 | 21 | These will be reviewed for inclusion in the site. The goal is to show a range of 22 | useful, real world queries without having lots of duplicates or very similar queries. 23 | 24 | ## Submitting a bug report 25 | 26 | Note that sometimes the Overpass API and Overpass Turbo applications 27 | might report errors due to server load. 28 | 29 | Please limit your bug reports to issues with the website (e.g. website formatting issues, spelling mistakes) 30 | or problems executing the queries. 31 | 32 | To submit a bug, please [file an issue](https://github.com/ldodds/osm-queries/issues) on github. 33 | 34 | It'd be help to provide details of what query you were running, the web page you were 35 | using and a description of the error encountered. 36 | -------------------------------------------------------------------------------- /for-local-mappers/benches.osm: -------------------------------------------------------------------------------- 1 | /* 2 | OpenBenches is a project to crowd-source inscriptions of benches 3 | around the world. All of the data is openly licensed. 4 | 5 | Data from OSM can be used to help with surveying benches to add to 6 | OpenBenches. And bench locations in OpenBenches could be used to help improve OSM as they're alway based on a local survey. Users are asked to submit a photo of the bench and/or its inscription. 7 | 8 | This query is intended to help anyone interested in improving the quality of bench coverage in either service. 9 | 10 | Benches with backrests might well have an inscription. 11 | 12 | Benches with inscriptions could be added to OpenBenches 13 | 14 | Benches that have been added to OpenBenches could have the id tagged. 15 | 16 | This report tries to summarise how well benches are tagged and the two services linked based on the current map view. 17 | 18 | Benches with an `inscription`, or an `inscription:url` tag and 19 | an `openbenches:id` are shown as green circles. These are complete. 20 | 21 | Benches with a green circle, but a white fill have an OpenBenches id but no `inscription` or `inscription:url` tag. Data is missing in OSM. 22 | 23 | Benches with an `inscription` tag but no `openbenches:id` are shown as orange circles. They could be surveyed and added to OpenBenches 24 | 25 | Benches with an orange circle and a yellow fill have a backrest, but don't have an `inscription` or `inscription:url` tag. There may be missing information in OSM that could be added if they were resurveyed. And they could be added to OpenBenches too. 26 | 27 | Benches with a grey circle and a white fill have no tags relating to backrests, inscriptions, etc. Tags might be missing. They could be checked so that `backrest=no` could be added. 28 | 29 | Benches that are in OpenBenches but are not in OSM are not shown :) 30 | 31 | Hopefully this might be useful as a small project? 32 | 33 | 34 | @title Mapping bench inscriptions 35 | @see https://wiki.openstreetmap.org/wiki/Key:openbenches:id 36 | @see https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dbench 37 | */ 38 | [bbox:{{bbox}}]; 39 | ( 40 | node["amenity"="bench"]; 41 | ); 42 | out body; 43 | 44 | {{style: 45 | 46 | node[amenity=bench] 47 | { color: grey; fill-color: white; fill-opacity: 1; opacity: 1} 48 | 49 | node[amenity=bench][backrest=yes][!inscription] 50 | { color: orange; fill-color: yellow; } 51 | 52 | node[amenity=bench][backrest=yes][!inscription:url] 53 | { color: orange; fill-color: yellow; } 54 | 55 | node[amenity=bench][inscription][!openbenches:id] 56 | { color: orange; fill-color: orange; } 57 | 58 | node[amenity=bench][openbenches:id][!inscription] 59 | { color: green; fill-color: white; } 60 | 61 | node[amenity=bench][openbenches:id][!inscription:url] 62 | { color: green; fill-color: white; } 63 | 64 | node[amenity=bench][openbenches:id][inscription] 65 | { color: green; fill-color: green; } 66 | 67 | node[amenity=bench][openbenches:id][inscription:url] 68 | { color: green; fill-color: green; } 69 | 70 | }} 71 | -------------------------------------------------------------------------------- /for-local-mappers/disused-places.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Query for nodes, ways and relations that use the disused tag namespace to indicate that they're no longer in use. 3 | 4 | This might be a useful query as a reminder for places to resurvey to check 5 | to see if they are still disused or may have reopened. 6 | 7 | @title Disused amenities and buildings 8 | @see https://wiki.openstreetmap.org/wiki/Key:disused 9 | */ 10 | [bbox:{{bbox}}]; 11 | ( 12 | nwr["disused:amenity"]; 13 | nwr["disused:building"]; 14 | nwr["disused:tourism"]; 15 | ); 16 | out body; 17 | >; 18 | out skel qt; 19 | -------------------------------------------------------------------------------- /for-local-mappers/high-street-recent-changes.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This is a variation of the query that extract information about typical high street shops and amenities. 3 | 4 | Tt applies an additional filter to select just those nodes, ways and relations that have been changed since 5 | the 1st January 2021. 6 | 7 | It does this using the `newer` query filter which used to specify the full date-time of interest. 8 | 9 | The filter cannot be applied directly to the first union, so the initial results are assigned to a variables called "`highstreet`" 10 | and the filter is applied to that. 11 | 12 | @title The High Street, Recent changes 13 | */ 14 | [bbox:{{bbox}}]; 15 | ( 16 | nwr["building"="retail"]; 17 | nwr["building"="supermarket"]; 18 | nwr["building"="commercial"]; 19 | 20 | nwr["amenity"="pub"]; 21 | nwr["amenity"="bar"]; 22 | nwr["amenity"="restaurant"]; 23 | nwr["amenity"="cafe"]; 24 | nwr["amenity"="library"]; 25 | nwr["amenity"="bank"]; 26 | nwr["amenity"="fast_food"]; 27 | 28 | )->.highstreet; 29 | nwr.highstreet(newer:"2021-01-01T00:00:00Z"); 30 | out body; 31 | >; 32 | out skel qt; 33 | -------------------------------------------------------------------------------- /for-local-mappers/mismatched-streets.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query can be used to highlight issues with address data. 3 | 4 | It find features with an `addr:street` tag whose value doesn't match the name of local street. 5 | 6 | The intention is to highlight potential data errors. There may be reasons why 7 | the tags and values are different, but it might also highlight simple typos. 8 | 9 | Try adjusting it to use your local town by replacing "Bath" with a different name. 10 | 11 | This is adapted from an example given in the Overpass developer blog. It shows 12 | some advanced features of OverpassQL language including creating objects, 13 | manipulating sets and use of functions. 14 | 15 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Areas 16 | @see https://dev.overpass-api.de/blog/sliced_time_and_space.html 17 | @title Mismatched streets 18 | */ 19 | //find the area called Bath, saving to named set 20 | area[name="Bath"]->.a; 21 | 22 | //find all the ways tagged as highway in the named set 23 | way(area.a)[highway]; 24 | 25 | //make a temporary element called "stat". 26 | //give it a name tag whose value will be the set of all highway names 27 | //save it in another temporary result set called "all" 28 | make stat name=set(t["name"])->.all; 29 | 30 | //find any node, way or relation in the area we first matched 31 | nwr(area.a)["addr:street"]; 32 | 33 | //loop through all of the addr:street tags in the results 34 | //anything without a value for this tag will be ignored 35 | for (t["addr:street"]) 36 | { 37 | //Lots going on here, so to break it down: 38 | //`lrs_in` is a function that checks to see if its first argument can be found in the second 39 | //_.val is the current value of the `for` loop 40 | // all.u is the union of all name tag values in the "all" set. In short, the list of all streets 41 | // 42 | //So this conditional returns true if the value of the `addr:street` tag for 43 | //the current nodes is NOT in the list of names we found earlier 44 | if (!lrs_in(_.val, all.u(t["name"]))) 45 | { 46 | //output a point for the match 47 | //this is the node, or a centroid for ways/relations 48 | out center; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /for-local-mappers/overview.md: -------------------------------------------------------------------------------- 1 | If you're a local mapper, or running a local mapping project, then the Overpass API and 2 | Overpass Turbo can be helpful in allowing you to do things like: 3 | 4 | * find and correct simple errors in tagging 5 | * identify areas that may need to be resurveyed 6 | * visualise progress of a community mapping activity, e.g. to capture details about wheelchair access 7 | * extract useful sets of data to use in JOSM or other mapping tools 8 | 9 | This collection of queries is intended to collect together useful queries to support 10 | these types of use case. 11 | 12 | The API and tools aren't a substitute for directly meeting and coordinating as a community. 13 | And there are a variety of other tools, services and forums to help to monitor recent changesets or 14 | discuss projects. But a well crafted query might help guide some of that work. 15 | 16 | Feel free to [contribute any new queries](../contribute.html) or suggest queries 17 | for inclusion in the [discussion forum on github](https://github.com/ldodds/osm-queries/discussions). 18 | -------------------------------------------------------------------------------- /for-local-mappers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "For Local Mappers", 3 | "description": "Queries to support local mappers", 4 | "base-url": "https://osm-queries.ldodds.com/", 5 | "author": ["Leigh Dodds"] 6 | } 7 | -------------------------------------------------------------------------------- /for-local-mappers/quite-interesting-no-link.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Finds a range of potentially interesting, historic or noteworthy locations that don't have a Wikidata link. 3 | 4 | Of course, what you might consider interesting, historic or noteworthy might be different. And lack of a wikidata 5 | link doesn't mean that there is a wikidata entry to link to, or that the location should have one. 6 | 7 | But this might be a useful starting point to find locally significant places and either link them to wikidata, 8 | perhaps adding a new entry if useful. 9 | 10 | @title Interesting places without wikidata links 11 | @see https://wiki.openstreetmap.org/wiki/Key:wikidata 12 | @see https://wiki.openstreetmap.org/wiki/Key:tourism 13 | */ 14 | [bbox:{{bbox}}]; 15 | ( 16 | //historic locations 17 | nwr["historic"]; 18 | 19 | //tourist attractions 20 | nwr["tourism"="attraction"]; 21 | nwr["tourism"="artwork"]; 22 | nwr["tourism"="museum"]; 23 | 24 | //parks 25 | nwr["leisure"="park"]; 26 | 27 | //historic buildings 28 | nwr["amenity"="townhall"]; 29 | nwr["amenity"="university"]; 30 | 31 | )->.qi; 32 | nwr.qi["wikidata"!~"."]; 33 | out body; 34 | >; 35 | out skel qt; 36 | -------------------------------------------------------------------------------- /for-local-mappers/the-high-street.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Finds information for a selection of buildings and amenities that you might 3 | find on a typical UK high street. 4 | 5 | Helpful to review whether to add details like addresses, opening hours, websites 6 | and wheelchair access. 7 | 8 | The query uses the "nwr" specifier to query for (n)odes, (w)ays and (r)elations. Sometimes local businesses might 9 | only be tagged as points, in other cases the entire outline of a building might be drawn and tagged. This allows us to 10 | find information regardless of how its represented on the map. 11 | 12 | The query also uses a range of different filters to identify the information we're interested in. In this case a variety of 13 | `building=*` and `amenity=*` filters. The result will be the union of all nodes, ways and relations that have these tags. 14 | 15 | A global bounding box query filter is used to specify the 16 | location we are interested in. The special "{{bbox}}" syntax here means 17 | this query only works in Overpass Turbo which determines the bounding box based on your zoom level. 18 | 19 | Alternatively you could specify a fixed bounding box: `[bbox:("...")]` 20 | specifying the coordinates. 21 | 22 | @title The High Street 23 | @see https://en.wikipedia.org/wiki/High_Street 24 | */ 25 | [bbox:{{bbox}}]; 26 | ( 27 | nwr["building"="retail"]; 28 | nwr["building"="supermarket"]; 29 | nwr["building"="commercial"]; 30 | 31 | nwr["amenity"="pub"]; 32 | nwr["amenity"="bar"]; 33 | nwr["amenity"="restaurant"]; 34 | nwr["amenity"="cafe"]; 35 | nwr["amenity"="library"]; 36 | nwr["amenity"="bank"]; 37 | nwr["amenity"="fast_food"]; 38 | ); 39 | out body; 40 | >; 41 | out skel qt; 42 | -------------------------------------------------------------------------------- /licence.md: -------------------------------------------------------------------------------- 1 | # Licence 2 | 3 | The contents of this website have been placed into the public domain 4 | via [a CC0 Waiver](http://creativecommons.org/publicdomain/zero/1.0/). 5 | 6 | You may use, adapt or redistribute this work as you see fit. 7 | 8 | If you'd like to acknowledge the work put into the development of the site and 9 | its content, then a link would be appreciated. 10 | -------------------------------------------------------------------------------- /map-css/brondby.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This is Brøndby Haveby near Copenhagen. I just thought they looked a bit like flowers. 3 | 4 | This demonstrates building up a more complex query to select and then style 5 | a collection of nodes, ways and relations. 6 | 7 | @title Brøndby Haveby 8 | @see https://www.lonelyplanet.com/articles/broendby-haveby-denmark-from-above 9 | */ 10 | [bbox:55.6342, 12.39277, 55.63981, 12.40409]; 11 | ( 12 | way["highway"="living_street"]["name"~"^Lille|Store"]; 13 | >; 14 | way["highway"="residential"]["name"="Store Harekærvej"]; 15 | >; 16 | node["addr:street"~"^Lille|Store"]; 17 | >; 18 | way["amenity"="parking"]; 19 | >; 20 | relation(6323434); 21 | >; 22 | ); 23 | out body; 24 | 25 | {{style: 26 | 27 | way[highway] { color: #654321; opacity: 1; } 28 | way[amenity=parking] { fill-color: yellow; fill-opacity: 1; color: yellow;} 29 | way[role=inner] { fill-color: green; width: 0; } 30 | relation { opacity: 0; fill-color: green; fill-opacity: 1; } 31 | way[barrier=hedge] { opacity: 0; } 32 | node{ color:red; opacity: 1; fill-color: red; fill-opacity: 1;} 33 | node[highway] { fill-color: orange; opacity: 0; } 34 | node[@id=3728284045] { opacity: 0; fill-opacity: 0;} 35 | }} 36 | -------------------------------------------------------------------------------- /map-css/lotus-bahai-temple.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Colouring the Lotus Bahai Template as a lotus flower. 3 | 4 | This example illustrates selecting the same way more than once (44827278). In 5 | the second selection we output just its centroid and then style that using 6 | `way:placeholder`. 7 | 8 | We also hide nodes that are selected using the `>` recurse operator so they're 9 | not displayed. 10 | 11 | @see https://www.openstreetmap.org/way/44827278 12 | @see https://en.wikipedia.org/wiki/Lotus_Temple 13 | @title Lotus Bahai Temple 14 | */ 15 | [bbox:28.55215, 77.2574, 28.55433, 77.26023]; 16 | ( 17 | way(44827278); //inner 18 | >; 19 | way["landuse"="basin"]; 20 | >; 21 | way(119871876); //outer 22 | >; 23 | way(119912480); 24 | >; 25 | way(119912477); 26 | >; 27 | way(119912471); 28 | >; 29 | way(119912474); 30 | >; 31 | way(119912468); 32 | >; 33 | way(119912479); 34 | >; 35 | way(119912469); 36 | >; 37 | way(484723872); //entry path 38 | >; 39 | way(119871864); //stem 40 | >; 41 | way(484723864); 42 | >; 43 | way(484723863); 44 | >; 45 | way(119871875); 46 | >; 47 | way(44278200); //outer way 48 | >; 49 | ); 50 | out body; 51 | 52 | way(44827278); 53 | out center; 54 | 55 | {{style: 56 | way 57 | { fill-color: #E75480; fill-opacity: 1; opacity: 1; color:#E75480; width: 5;} 58 | 59 | way[@id=44827278] 60 | { fill-color: orange; fill-opacity: 1; opacity: 1; color:#F8C377; width: 5;} 61 | 62 | way[landuse=basin] 63 | { fill-color: #FADADD; dashes: 5,8; fill-opacity: 1; opacity: 1; color: #FFc0CB; width: 5; } 64 | 65 | way[@id=119871876] 66 | { fill-color: #E75480; fill-opacity: 1; opacity: 1; color:#E75480; width: 5;} 67 | 68 | way[@id=484723872] 69 | { opacity: 1; color:green; width: 5;} 70 | 71 | way[@id=119871864] 72 | { opacity: 1; color:green; width: 5;} 73 | 74 | way[@id=484723864] 75 | { opacity: 1; color:green; width: 5;} 76 | 77 | way[@id=484723863] 78 | { opacity: 1; color:green; width: 5;} 79 | 80 | way[@id=119871875] 81 | { opacity: 1; color:green; width: 5;} 82 | 83 | way[building=temple] 84 | { opacity: 1; colour:blue; } 85 | 86 | way[@id=44278200] { fill-color: white; color: white; } 87 | way:placeholder { fill-color: yellow; } 88 | node[entrance=yes] { opacity: 0; } 89 | node[entrance=main] { opacity: 0; } 90 | }} 91 | -------------------------------------------------------------------------------- /map-css/overview.md: -------------------------------------------------------------------------------- 1 | There are a variety of languages for applying declarative styling to maps. 2 | 3 | [MapCSS](https://wiki.openstreetmap.org/wiki/MapCSS) is a CSS style language that 4 | is supported in a number of different OSM editors and applications. 5 | 6 | Overpass Turbo supports styling of query results using MapCSS. While it has 7 | [some restrictions on the supported features](https://wiki.openstreetmap.org/wiki/Overpass_turbo/MapCSS) 8 | it can still be a useful way to quickly generate interactive maps directly from the 9 | IDE. 10 | 11 | With that in mind, this collection of queries demonstrates some of the MapCSS 12 | syntax. 13 | 14 | It includes a mixture of basic examples, as well as some more creative uses. 15 | -------------------------------------------------------------------------------- /map-css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Styling with Map CSS", 3 | "description": "Examples of how to style query results using Map CSS", 4 | "base-url": "https://osm-queries.ldodds.com/", 5 | "author": ["Leigh Dodds"] 6 | } 7 | -------------------------------------------------------------------------------- /map-css/styling-nodes.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query selects shops and amenities within the Colosseum in Rome. 3 | 4 | The query selects any node with either the shop or amenity tag. The 5 | MapCSS then styles the nodes based on their tags and values. This highlights 6 | that the interpreter has access to all of the data about a map feature. 7 | 8 | The styling does the following: 9 | 10 | * provides a fallback to style any unexpected nodes as red 11 | * styles drinking water fountains as blue circles 12 | * styles shops as black circles with a green fill 13 | * styles toilets by displaying an (oversized!) icon 14 | 15 | For icons, Overpass Turbo has three sets available. See the links below. 16 | 17 | Note, the ordering of the styles is important. They're applied in order. so 18 | if we'd put the fallback style (the red circle) at the end then that's all we'd 19 | see. You can try it. 20 | 21 | If you're wondering. Its a wastebin. 22 | 23 | @title Styling nodes 24 | @see https://wiki.openstreetmap.org/wiki/Overpass_turbo/MapCSS 25 | @see https://github.com/tyrasd/overpass-turbo/tree/master/icons 26 | */ 27 | [bbox:41.88926, 12.49109, 41.8911, 12.49392]; 28 | ( 29 | node["shop"]; 30 | node["amenity"]; 31 | ); 32 | out body; 33 | 34 | //MapCSS styles 35 | {{style: 36 | node { fill-color: red; color: red; fill-opacity: 1;} 37 | node[amenity=drinking_water] { fill-color: blue; color: blue, fill-opacity 1;} 38 | node[shop] { fill-color: green; fill-opacity 1; color: black } 39 | node[amenity=toilets] { icon-image: url("icons/maki/toilets-24.png"); icon-width: 50;} 40 | }} 41 | -------------------------------------------------------------------------------- /map-css/the-bath-key.osm: -------------------------------------------------------------------------------- 1 | /* 2 | John Wood, the Elder had a big influence on the architecture and design of 3 | Bath. Many of the buildings he designed into masonic symbols and icons. 4 | 5 | His design for the Circus, Gay Street and Queen Squre in Bath creates the 6 | shape of a key. 7 | 8 | This query selects the ways and relations that define that shape in the 9 | OSM database and then uses MapCSS to style them. 10 | 11 | @see https://en.wikipedia.org/wiki/John_Wood,_the_Elder 12 | @title Bath's Hidden Key 13 | */ 14 | [bbox:51.38097, -2.36957, 51.38716, -2.35825]; 15 | ( 16 | way(49549786); 17 | >; 18 | way(49549785); 19 | >; 20 | way(120948853); //grass 21 | >; 22 | way(3609799); //gay street 23 | >; 24 | way(30992002); //qs 25 | >; 26 | way(210); 27 | >; 28 | way(331545472); 29 | >; 30 | way(773250139); 31 | >; 32 | way(131628669); 33 | >; 34 | way(59967625); 35 | >; 36 | relation(1338997); 37 | >; 38 | ); 39 | 40 | out body; 41 | 42 | {{style: 43 | way 44 | { color:rgb(99,73,23); width:4; opacity:1; } 45 | 46 | way[@id=120948853] 47 | { color:rgb(99,73,23); width:2; opacity:1; } 48 | 49 | node 50 | { opacity: 0; } 51 | 52 | relation 53 | { color:rgb(99,73,23); width:2; opacity:1; } 54 | }} 55 | -------------------------------------------------------------------------------- /map-css/ways-as-areas.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query selects the unnamed standing stones at Stonehenge. It 3 | then styles the results using MapCSS. 4 | 5 | It demonstrates all the basic properties that can control the 6 | fill of a shape 7 | 8 | * `fill-color` - defines the colour of the fill. Either as a named colour, or as a hex (e.g. `#000000`) or RGB value (e.g. `rgb(99,73,23)`) 9 | * `fill-opacity` - is a value between 0-1 10 | 11 | You'll notice that Overpass Turbo will apply its default styles to the shapes 12 | so there will be a different colour outline to the stones. 13 | 14 | Try adjusting the query to use this instead: 15 | 16 | ``` 17 | way { color: brown; fill-color: brown; opacity: 1; fill-opacity: 1 } 18 | ``` 19 | 20 | @title Style ways, as areas 21 | */ 22 | [bbox:51.17798, -1.82733, 51.17953, -1.8245]; 23 | ( 24 | //select the ways and their nodes 25 | way[!"name"]["historic"="stone"]; 26 | >; 27 | ); 28 | out body; 29 | 30 | //MapCSS styles 31 | {{style: 32 | way { fill-color: brown; fill-opacity: 1 } 33 | }} 34 | -------------------------------------------------------------------------------- /map-css/ways-as-lines.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query selects the embankments that surround Stonehenge. It 3 | then styles the results using MapCSS. 4 | 5 | It demonstrates all the basic properties that can control the 6 | display of lines. 7 | 8 | * `color` - defines the colour of a line. Either as a named colour, or as a hex (e.g. `#000000`) or RGB value (e.g. `rgb(99,73,23)`) 9 | * `dashes` - specifies a dashed line. use two values, the first is length of line that is drawn, the second is the length of the gap 10 | * `opacity` - is a value between 0-1 11 | * `width` - defines the width of the line 12 | 13 | @title Style ways, as lines 14 | */ 15 | [bbox:51.17798, -1.82733, 51.17953, -1.8245]; 16 | ( 17 | //select the ways and their nodes 18 | way["man_made"="embankment"]; 19 | >; 20 | ); 21 | out body; 22 | 23 | //MapCSS styles 24 | {{style: 25 | way { color: green; dashes: 5,8; opacity: 1; width: 5; } 26 | }} 27 | -------------------------------------------------------------------------------- /misc/all-the-things.osm: -------------------------------------------------------------------------------- 1 | /* 2 | @title Extract all data within the bounding box 3 | */ 4 | [out:json][timeout:25]; 5 | ( 6 | node({{bbox}}); 7 | way({{bbox}}); 8 | relation({{bbox}}); 9 | ); 10 | out body; 11 | >; 12 | out skel qt; 13 | -------------------------------------------------------------------------------- /misc/export-statues.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Find bronze statues, sculptures, busts and memorials and then outputs a CSV 3 | file of the results. 4 | 5 | @title Export bronze statues as CSV 6 | @see https://twitter.com/ldodds/status/1056125234267471872 7 | */ 8 | [out:csv( ::id, ::lat, ::lon, name, artwork_type, description, artist_name, start_date, wikidata; TRUE; "|") ][timeout:60]; 9 | // gather results 10 | ( 11 | //find any statues, sculptures or busts made of bronze 12 | node["material"="bronze"][~"artwork_type"~"^statue|sculpture|bust$"]; 13 | //also find any memorial statues made of bronze 14 | node["material"="bronze"]["memorial"="statue"]; 15 | 16 | ); 17 | // print results 18 | out body; 19 | >; 20 | out skel qt; 21 | -------------------------------------------------------------------------------- /misc/geocode-area.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Finds cities and towns in Somerset 3 | 4 | This query uses an Overpass Turbo extension called `geocodeArea`. It accepts 5 | a search term as a parameter and attempts to match that against the name of an 6 | area. 7 | 8 | Areas are not present in the basic OpenStreetMap database. They're constructed 9 | as part of loading data into the database that serves the Overpass API. So, while 10 | they are derived from real map features they don't exist as something you can edit. 11 | 12 | Areas are used to provide some additional functionality, such as searching for 13 | places by name, finding features within areas, etc. 14 | 15 | @see https://wiki.openstreetmap.org/wiki/Overpass_turbo/Extended_Overpass_Turbo_Queries 16 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Areas 17 | @see https://wiki.openstreetmap.org/wiki/Nominatim 18 | @title Geocode Area 19 | */ 20 | [out:json][timeout:25]; 21 | {{geocodeArea:Somerset}}->.searchArea; 22 | ( 23 | node["place"="town"](area.searchArea); 24 | node["place"="city"](area.searchArea); 25 | ); 26 | out body; 27 | >; 28 | out skel qt; 29 | -------------------------------------------------------------------------------- /misc/grindelwald-glacier.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Extract the nodes, ways and relations tagged as a glacier near the 3 | Grindelwald Glacier in Switzerland. 4 | 5 | @title Extract glacier features as a specific location 6 | @see https://en.wikipedia.org/wiki/Upper_Grindelwald_Glacier 7 | @tags glacier 8 | */ 9 | [out:json][timeout:25][bbox:46.5914,8.0828,46.6301, 8.1674]; 10 | // gather results 11 | ( 12 | // query part for: “natural=glacier” 13 | nwr["natural"="glacier"]; 14 | ); 15 | // print results 16 | out body; 17 | >; 18 | out skel qt; 19 | -------------------------------------------------------------------------------- /misc/overview.md: -------------------------------------------------------------------------------- 1 | A random selection of queries that don't yet have a better home on the site. 2 | -------------------------------------------------------------------------------- /misc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Miscellaneous", 3 | "description": "A home for all the other queries", 4 | "base-url": "https://osm-queries.ldodds.com/", 5 | "author": ["Leigh Dodds"] 6 | } 7 | -------------------------------------------------------------------------------- /misc/playgrounds-with-styles.osm: -------------------------------------------------------------------------------- 1 | /* 2 | @title Find playgrounds, add styling 3 | */ 4 | [out:json][timeout:25]; 5 | // gather results 6 | ( 7 | // query part for: “leisure=playground and access!=no and access!=private” 8 | node["leisure"="playground"]["access"!="no"]["access"!="private"]({{bbox}}); 9 | way["leisure"="playground"]["access"!="no"]["access"!="private"]({{bbox}}); 10 | relation["leisure"="playground"]["access"!="no"]["access"!="private"]({{bbox}}); 11 | ); 12 | // print results 13 | out body; 14 | >; 15 | out skel qt; 16 | 17 | {{style: 18 | way{ 19 | color: green; 20 | fill-color: green; 21 | text: name:en; 22 | } 23 | node{ 24 | color: green; 25 | fill-color: green; 26 | text: name:en; 27 | } 28 | relation{ 29 | color: navy; 30 | fill-color: green; 31 | text: name:en; 32 | } 33 | relation node, relation way, relation relation { 34 | color: green; 35 | fill-color: green; 36 | } 37 | }} 38 | -------------------------------------------------------------------------------- /misc/playgrounds.osm: -------------------------------------------------------------------------------- 1 | /* 2 | @title Find playgrounds 3 | */ 4 | [out:json][timeout:25]; 5 | // gather results 6 | ( 7 | // query part for: “leisure=playground and access!=no and access!=private” 8 | nwr["leisure"="playground"]["access"!="no"]["access"!="private"]({{bbox}}); 9 | ); 10 | // print results 11 | out body; 12 | >; 13 | out skel qt; 14 | -------------------------------------------------------------------------------- /overview.md: -------------------------------------------------------------------------------- 1 | [OpenStreetMap](https://openstreetmap.org) is an openly licensed geospatial database. It's regularly used in 2 | a very wide range of applications that include some of the smallest and largest 3 | sites you'll find on the web. 4 | 5 | If you're using OpenStreetMap as a base map, then there are dozens of ways 6 | that you can integrate it into your web application. Similarly, if you're 7 | doing complex analysis of the data then you'll be taking extracts to process and 8 | index locally. There are lots of tools and services to help you achieve both of those 9 | things. 10 | 11 | But many potential uses of the data lie somewhere in between: you just want to do 12 | relatively small queries of the database to extract some data for a quick analysis, 13 | build a simple map or support you in keeping the data up to date. 14 | 15 | ## The Overpass API, OverpassQL and Overpass Turbo 16 | 17 | For that you'll need to use the [Overpass API](https://wiki.openstreetmap.org/wiki/Overpass_API). 18 | This is an openly accessible API that supports queries against the live OSM database (and in some 19 | cases, also against historical data). 20 | 21 | You can use the API to integrate OSM data directly into your application. GIS tools 22 | like [QGIS also allow you to work with the API](https://docs.qgis.org/3.16/en/docs/training_manual/qgis_plugins/plugin_examples.html), bringing data directly into your workspace. 23 | 24 | There's also a freely available web based IDE called [Overpass Turbo](https://overpass-turbo.eu/) 25 | that can help you write and run queries, save and share them and explore results. 26 | 27 | But, to get the most from those tools and the API you'll need to learn how to write 28 | queries using a custom query language called [Overpass QL](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL). 29 | 30 | ## An openly licensed collection of Overpass queries 31 | 32 | This website provides collections of OverpassQL queries to help you to learn the 33 | language and explore the features. 34 | 35 | Each of the themed collections includes a number of Overpass queries that you can 36 | immediately load and run via the Overpass Turbo editor. The collection also includes 37 | a worked tutorial that covers the core syntax of the language. 38 | 39 | All of the content and queries are [in the public domain](licence.html) so can be 40 | freely reused, shared or adapted as you see fit. 41 | 42 | [Read more about the goals of this website](background.html). 43 | 44 | ## Contribute 45 | 46 | The content and source for this website is completely open. The intention is to update 47 | the website with new examples and tutorials over time. 48 | 49 | If you're interested in contributing to that work, then read [how to contribute](contribute.html). 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "OSM Queries", 3 | "description": "A collection of queries to help you use the OpenStreetMap Overpass API", 4 | "base-url": "https://osm-queries.ldodds.com/", 5 | "author": ["Leigh Dodds"], 6 | "extra-files": { 7 | "label": "About", 8 | "files": [ 9 | { "label": "Background", "file": "background.md" }, 10 | { "label": "Syntax Reference", "file": "syntax-reference.md" }, 11 | { "label": "Contribute", "file": "contribute.md" }, 12 | { "label": "Licence", "file": "licence.md" }, 13 | { "label": "Colophon", "file": "colophon.md" } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /syntax-reference.md: -------------------------------------------------------------------------------- 1 | # OverpassQL Syntax Reference 2 | 3 | A concise syntax reference for [the OverpassQL language](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL). 4 | 5 | ## Comments 6 | 7 | ``` 8 | //single-line comment 9 | /* multi line comment */ 10 | ``` 11 | 12 | ## Escaping 13 | 14 | * `\n` escapes a newline 15 | * `\t` escapes a tabulation 16 | * `\"` or `\'` escapes the respective quotation mark 17 | * `\\` escapes the backslash 18 | * `\u####` escapes a unicode UTF-16 value. 19 | 20 | ## Statements 21 | 22 | Statements are terminated by a semi-colon (`;`). 23 | 24 | A statement consist of either a _query setting_, a _keyword statement_ or a _block statement_ statement terminated by a semi-colon (`;`). 25 | 26 | A statement might include _filters_. 27 | 28 | Block statements and query filters might include _functions_. 29 | 30 | ## Query Setting 31 | 32 | Must appear as the first uncommented statement in a query. Syntax is of the form: 33 | 34 | ``` 35 | [setting:value][setting2:value2][setting3:value3]...; 36 | ``` 37 | [Settings](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#Settings) include: `bbox`, `out`, `timeout`, `date`, `diff`, `adiff`, `maxsize`. 38 | 39 | Legal values vary by setting. 40 | 41 | ## Keyword Statements 42 | 43 | A keyword statement is a either a _query statement_ or a _simple statement_. 44 | The keyword may optionally be preceded by the name of a set. And may be 45 | followed by _filters_ or parameters. The optionality, number and syntax for these filters 46 | and parameters varies by statement. 47 | 48 | A keyword statement typically reads from and writes to a named set. Unless otherwise 49 | specified the statement will manipulate the default set (`._`) 50 | 51 | In general, the syntax for specifying input and output sets for a keyword statement 52 | is: 53 | 54 | ``` 55 | .input x ->.output; 56 | ``` 57 | 58 | Where `.input` specifies the input set for a statement named `x`. And where 59 | the assignment operator (`->`) is used to name the output set (`.output`). 60 | 61 | However query statements use an alternate syntax for defining their input set. 62 | 63 | ### Query statements 64 | 65 | These statements read from the OSM database by default, rather than a named 66 | set. Their output can be assigned to a named set, or are added to the default 67 | set if not specified. 68 | 69 | | Query Statement | Description | 70 | |-----------|-------------| 71 | |`node`|Find nodes 72 | |`way`|Find ways 73 | |`rel`|Find relations 74 | |`nwr`|Find nodes, ways, or relations 75 | |`nw`|Find nodes or ways 76 | |`nr`|Find nodes or relations 77 | |`wr`|Find ways or relations 78 | |`area`|Find areas 79 | |`<`|Recurse up 80 | |`<<`|Recurse up relations 81 | |`>`|Recurse down 82 | |`>>`|Recurse down relations 83 | 84 | While the recursion operators use the standard _keyword statement_ syntax for 85 | defining input and output sets, the _query statements_ for finding nodes, ways, 86 | relations and areas use a different syntax. 87 | 88 | For example: 89 | 90 | ``` 91 | node.input ->.output; 92 | ``` 93 | 94 | Where `.input` specifies the set against which the `node` statement will 95 | execute (applying any filters). And results are added to a set called `.output`. 96 | 97 | **Note**: this syntax is described as a filter in the OverpassQL language reference, 98 | but is arguably better considered as specifing the input to the query. 99 | 100 | ### Simple statements 101 | 102 | Other statements only manipulate sets: 103 | 104 | | Simple Statement | Description | 105 | |-----------|-------------| 106 | |`out`|Output the contents of a set. Required to get any output at all| 107 | |`.x;`|Reference to contents of the named set `.x`. Used in set arithmetic 108 | |`is_in`|Find areas that cover a lat/lng or nodes in a named set 109 | |`timeline`|Lookup version history of an object 110 | |`local`|Convert input into representation of OSM data 111 | |`convert`|Creates elements from its input set, adding or filters tags 112 | |`make`|Make a new element, e.g. a node, way or relation, or arbitrary object holding name-value pairs 113 | |`derived`|Query for derived objects? 114 | 115 | ## Block Statements 116 | 117 | Block statements are one of the following. 118 | 119 | |Statement|Syntax|Description| 120 | |---------|------|-----------| 121 | |Union|`(statement1; statement2; ...)`|Set union of the results of one or more statements| 122 | |Difference|`(statement1; - statement2;)`|Set difference between two statements| 123 | |If|`if (...evaluator...) { ... } else { ... }`|If statement, with optional else. See _evaluator_ 124 | |For Each|`foreach { ... }`|Performs block for each statement of its input set 125 | |For|`for (...evaluator...) { ... } `|Perform block of statements for each subset returned by its _evaluator_. 126 | |Complete|`complete {...}`|Loop repeatedly until results of substatements no longer change. 127 | |Retro|`retro (...evaluator...) {...}`|Perform block for dates specified by _evaluator_ 128 | |Compare|`compare (...evaluator...) {...}`|Compare diff of two timestamps. Evaluator and statement block are optional 129 | 130 | **Note**: there is no Intersection block statement. The closest is to use a _query statement_ of 131 | the form: `node.set1.set2` 132 | 133 | The If and Retro statements do not read or write to sets. (Or this remains 134 | undocumented if so). 135 | 136 | The Union, Difference, For Each, For and Complete and Compare block statements 137 | write to the default set, unless a named set is specified via the `->` operator. 138 | But the syntax varies: 139 | 140 | * Union and Difference use the basic syntax, e.g. `(...)->.output;` 141 | * For the others, which have blocks (`{}`), the `->` operator is appended to the keyword 142 | 143 | E.g. to direct the output of a For Each statement use: 144 | 145 | ``` 146 | foreach->.output {statements} 147 | ``` 148 | 149 | The For Each, For, Complete and Compare block statements all read values from the 150 | default set, unless a named set is specified instead. 151 | 152 | * The Compare statement uses the default _keyword statement_ syntax, e.g: `.input compare()->.output;` 153 | * Whereas the others use a dotted syntax similar to _query statements_ 154 | 155 | E.g. to specify that a For Each statement reads from `.input` and writes to `.output` 156 | use this syntax: 157 | 158 | ``` 159 | foreach.input->output { ... } 160 | ``` 161 | 162 | Within a `for` loop, the current value of the loop is assigned to a variable 163 | called `val` which is attached to the output set. 164 | 165 | For example with a `for` loop reading from `.input` and writing to `.output` within the block the 166 | value of `.output.val` is the current value of the evaluator. 167 | 168 | ``` 169 | for.input->output { ... .output.val is available here ... } 170 | ``` 171 | 172 | ##Filters 173 | 174 | Filters can be applied to _query statements_ to limit the query results in various 175 | ways. 176 | 177 | ### Tag Filters 178 | 179 | Tag filters are applied to the tags (name-value pairs) associated with the objects being queried. 180 | 181 | The use square brackets (`[]`). Names, values and regular expressions can optionally be 182 | wrapped in double or single quotes. Quotes must be used if there is a space in the value. 183 | 184 | |Filter|Description| 185 | |------|-----------| 186 | |`["name"]`|The `name` tag must be present on the object 187 | |`[!"name"]`|The `name` tag must not be present 188 | |`["name"="value"]`|The `name` tag must have the value `value` 189 | |`["name"!="value"]`|The `name` tag must not have the value `value` 190 | |`["name"~"regex"]`|The value of the `name` tag must match `regex` 191 | |`["name"~"regex", i]`|As above, but case insensitive. 192 | |`["name"~"^$"]`|The `name` tag has no value. Regex to match empty string. Only way to test for empty values. 193 | |`[~"name-regex"~"value-regex"]`|Apply the `value-regex` to any tag that matches `name-regex` 194 | |`[~"name-regex"~"value-regex", i]`|As above, but case insensitive 195 | 196 | [POSIX Extended](https://en.wikipedia.org/wiki/Regular_expression#POSIX_basic_and_extended) regular 197 | expressions are supported. Use the `^` and `$` symbols to match start and end of strings. `|` to 198 | specify alternatives, etc. 199 | 200 | ### Identity Filter 201 | 202 | Uses `()` brackets. 203 | 204 | Limit results to the objects that have a specified id, e.g. `node(1)` 205 | 206 | Limit results to one or more objects: `node(id:1, 2, 3)` 207 | 208 | The second is more efficient than multiple individual identity filters for the same 209 | object type. 210 | 211 | ### Spatial Filters 212 | 213 | Spatial filters use rounded brackets (`()`). The following spatial filters are 214 | supported. 215 | 216 | |Filter|Syntax|Description| 217 | |------|------|-----------| 218 | |Bounding Box|`(south, west, north, east)`|Filter based on bounding box specified by four coordinates 219 | |Around|`(around:radius,lat,lng)`|Filter to objects within circle defined by centroid `lat`, `lng` and `radius` 220 | |Around|`(around.input:radius)`|Filter to objects that are within `radius` distance of objects in `.input` set 221 | |Around|`(around:radius,lat1,lng1,lat2,lng2,...,latn,lngn)`|Filter to objects with `radius` distance of a linestring 222 | |Polygon|`(poly:"lat1 lng1 lat2 lng2 ... latn lngn")`|Filter to objects within a polygon 223 | 224 | ### Area Filters 225 | 226 | Filters objects to those that are spatially contained within an area. 227 | 228 | This is different to _member filters_ that look at parent-child relationships within the OSM data model. 229 | 230 | Also note that the `area` filter is different to the `area` _query statement_. The latter queries for 231 | areas, to fetch them from the database. Whereas the former is used to do a spatial filter on a result set. 232 | 233 | The `area` filter uses rounded brackets (`()`). 234 | 235 | |Syntax|Description| 236 | |------|-----------| 237 | |`(area)`|Filter based on whether objects are within areas in the default set 238 | |`(area.input)`|Filter based on whether objects are within an area stored in the named set (`.input`) 239 | |`(area:nnnnnnn)`|Filter to objects contained within a specific area, identified by is database id 240 | 241 | The `pivot` filter is related to the `area` filter. It is used to select the OSM database 242 | object that corresponds to the area(s) contained in a result set: 243 | 244 | ``` 245 | way(pivot) //find ways that correspond to areas in the default set 246 | way(pivot.input) //find ways that correspond to areas in set called 'input' 247 | ``` 248 | 249 | ### Date Filters 250 | 251 | Date filters use rounded brackets (`()`). 252 | 253 | |Filter|Syntax|Description| 254 | |------|------|-----------| 255 | |Newer|`(newer:"YYYY-mm-ddTHH:MM:ssZ")`|Filter to objects that have changed since specified date-time 256 | |Changed|`(changed:"YYYY-mm-ddTHH:MM:ssZ")`|Filter to objects that have changed between date-time and current time 257 | |Changed|`(changed:"YYYY-mm-ddTHH:MM:ssZ","YYYY-mm-ddTHH:MM:ssZ")`|Filter to objects that have changed between two dates 258 | 259 | ### Member (Recursion) Filters 260 | 261 | The recursion filters use rounded brackets (`()`). 262 | 263 | In the OSM data model. Nodes can be children of ways and relations. Ways can be children 264 | of relations. Relations can be children of other relations. These relationships can be 265 | qualifed by a role. 266 | 267 | The member filters allow traversal between parent and child objects via these relationships. 268 | 269 | They are used to select objects of different types, based on whether they are members of 270 | the objects in their input set. 271 | 272 | The input set is the default set (`._`) unless specified by dotted syntax. For example to 273 | find nodes in the OSM database that are members of ways found in a set called `.input`: 274 | 275 | ``` 276 | node(w.input); 277 | ``` 278 | 279 | |Name|Filter|Example|Description| 280 | |----|------|-------|-----------| 281 | |Members of ways|`(w)`|`node(w)`|Select child nodes of ways from input set 282 | |Members of relations|`(r)`|`node(r)`|Select node members of relations in input set 283 | |Members of relations|`(r)`|`way(r)`|Select way members of relations in input set 284 | |Parents of nodes|`(bn)`|`way(bn)`|Select parent ways from nodes in input set 285 | |Parents of nodes|`(bn)`|`rel(bn)`|Select parent relations of nodes in input set 286 | |Parents of ways|`(bw)`|`rel(bw)`|Select parent relations of ways in input set 287 | |Parents of relations|`(br)`|`rel(br)`|Select parent relations of relations in input set 288 | 289 | The filters can be further qualified by role: 290 | 291 | ``` 292 | r:"x" //members of relations via a role called 'x' 293 | r:"" //members of relations with empty role 294 | r.input:"x" //members of relations in a set called input, with role 'x' 295 | r.input:"" //members of relations in a set called input, with empty role 296 | ``` 297 | 298 | ### User Filter 299 | 300 | Filter objects by the user associated with most recent change. 301 | 302 | |Filter|Syntax|Description| 303 | |------|------|-----------| 304 | |User|`(user:"name")`|Filter objects last touched by user name `name` 305 | |User|`(uid:id)`|Filter objects last touched by user id `id` 306 | 307 | ### Conditional Filter 308 | 309 | Filter objects based on a custom expression. Objects for which the expression 310 | does not return true will be filtered from the results. 311 | 312 | ``` 313 | (if: expression) 314 | ``` 315 | 316 | Where expression is an _evaluator_ that returns a boolean value. 317 | 318 | ## Expressions (Evaluators) 319 | 320 | Expressions consist of _functions_ and operators. 321 | 322 | ### Operators 323 | 324 | |Operator|Description| 325 | |--------|-----------| 326 | |`!`, `||`, `&&`|Boolean logic 327 | |`-`, `+`, `/`, `*`|Mathematical operators 328 | |`==`, `!=`|Equality operators 329 | |`<`, `<=`, `>`, `>=`|Comparisons 330 | |`expr ? x : y`|Ternary operator 331 | 332 | ## Functions 333 | 334 | |Function|Description| 335 | |--------|-----------| 336 | |`angle()`|Calculates angle between two segments in a way 337 | |`center(...)`|Calculates centre of the bounding box of its input 338 | |`changeset()`|Returns the id of the changeset for last update to an object 339 | |`count(...)`|Count objects of the type specified in its parameter, which will be one of `nodes`, `ways`, `relations`, `deriveds`, `nwr`, `nw`, `wr`, `nr` 340 | |`count_by_role()`|Count number of members with a specific role 341 | |`count_distinct_members()`|Count number of distinct members 342 | |`count_distinct_by_role()`|Count number of distinct members with a specific role 343 | |`count_members()`|Count number of members for an object 344 | |`count_tags()`|Count tags for an object 345 | |`date(...)`|Turns its argument into a number representing a date, for comparison purposes only 346 | |`gcat(...)`|Calculate combined geometry from its input set 347 | |`geom()`|Returns geometry of an object 348 | |`hull(...)`|Returns the convex hull of its argument 349 | |`id()`|Returns OSM id of an object 350 | |`is_closed()`|Returns 1 if a way is closed, 0 others. Closed means the first and last node are the same. 351 | |`is_date(...)`|Tests whether its argument represents a date 352 | |`is_number(...)`|Returns 1/0 depending on which its argument is a number 353 | |`is_tag("name")`|Return 1 if an object has a tag called `name`. Otherwise 0. 354 | |`keys()`|Returns keys for a given object 355 | |`lat()`|Latitude of an object (or its bounding box centroid) 356 | |`length()`|Returns length of an object. Will be length of a way or all ways in a relation 357 | |`lon()`|Longitude of an object (or its bounding box centroid) 358 | |`lrs_in(...,...)`|Returns 1 if its first argument is contained in the set provided as a second argument 359 | |`lrs_isect(...,...)`|Returns the intersection of its two arguments, treated as sets 360 | |`lrs_min(...)`|Returns the minimum of the elements in its argument 361 | |`lrs_max(...)`|Returns the maximum of the elements in its argument 362 | |`lrs_union(...,...)`|Returns the union of its two arguments, treated as sets 363 | |`lstr(..,..)`|Returns linestring constructed from its arguments 364 | |`min(...)`|Returns minimum value in the set provided as a parameter 365 | |`max(...)`|Returns maximum value in the set provided as a parameter 366 | |`number(...)`|Convers argument to a number, or "NaN" 367 | |`per_member(...)`|Executes its argument once per member of the element 368 | |`per_vertex(...)`|Executes its argument once per vertex of the element 369 | |`poly(..,..)`|Returns a polygon constructed from its arguments 370 | |`pos()`|Position for a member within an element 371 | |`pt(lat,lng)`|Returns a valid OSM node geometry for given location 372 | |`set(...)`|Returns semi-colon list of all distinct values in its input 373 | |`suffix(...)`|Returns any value following a number in its input 374 | |`sum(...)`|Sums values in set provided as parameter 375 | |`timestamp()`|Returns timestamp of an object 376 | |`trace(...)`|Returns the trace of its argument? 377 | |`type()`|Returns type of an object. E.g. node or way 378 | |`t["name"]`|Returns value of the `name` tag 379 | |`u(...)`|??? 380 | |`uid()`|Returns user id of the user who last edited an object 381 | |`user()`|Returns user name of last editor of an object 382 | |`version()`|Returns version number of an object 383 | 384 | ## Overpass Turbo Extensions 385 | 386 | Overpass Turbo defines some extensions. These are like macros which are executed 387 | by the IDE and replaced with an appropriate value or statement. 388 | 389 | |Shortcut|Description| 390 | |--------|-----------| 391 | |`{{bbox}}`|Calculate a bounding box based on current map view| 392 | |`{{center}}`|Calculate center coordinates of current map view| 393 | |`{{date}}`|Current date and time 394 | |`{{date:specifier}}`|Create historical date based on `specifier`.Syntax is a number followed by a time period: second, minute, hour, days, weeks, months, years. E.g. `1 day`, `2 years` 395 | |`{{geocodeId:"query"}}`|Perform Nominatim search using `query`. Use OSM id of first result 396 | |`{{geocodeArea:"query"}}`|Perform Nominatim search using `query` for an area. Use OSM id of first area 397 | |`{{geocodeBbox:"query"}}`|Perform Nominatim search using `query`. Use the bounding box of the first result 398 | |`{{geocodeCoords:"query"}}`|Perform Nominatim search using `query`. Use the centroid of the first result 399 | |`{{style:...}}`|Define MapCSS styles to be applied to query results 400 | |`{{data:overpass,server=...}}`|Specify URL of Overpass API endpoint 401 | 402 | Custom macros can also be defined. Specify `{{shortcut=value}}` and all occurences of 403 | `{{shortcut}}` in the query will be replaced by `value`. 404 | -------------------------------------------------------------------------------- /tutorial/00-node-1.osm: -------------------------------------------------------------------------------- 1 | /* 2 | The OpenStreetMap data model consists of: 3 | 4 | * nodes - single points, e.g a postbox or tree 5 | * ways - a set of connected points, e.g. a path or a building 6 | * relations - a grouping of ways and nodes, e.g. a collection of buildings 7 | 8 | When you drill down from relations and ways you always end up with nodes. Nodes 9 | are the most basic element of the data model: a point on the map with some 10 | data attached to it as tags (name-value pairs). 11 | 12 | Our first query is one of the simplest possible OverpassQL queries. It select 13 | the node that has an `id` of `1` from the OSM database. It then outputs some 14 | information about that node. 15 | 16 | We'll learn more about different ways to query for nodes, ways and relations in 17 | other queries. 18 | 19 | And we'll also learn how to control what information is extracted and output 20 | from the database. 21 | 22 | But, for this first query, the main things to note is that a query consists of 23 | a series of statements. In this case there are two. Each statement ends with a semi-colon. 24 | 25 | The first statement (`node(1)`) performs the query. 26 | 27 | The second statement (`out`) creates the output. 28 | 29 | An OverpassQL query is a list of statements that are executed by the API. More complex 30 | queries will consist of many more statements of different types. These statements build 31 | up sets of results that are then returned to the user. 32 | 33 | The Overpass Turbo IDE helpfully displays those results on a map, where it can. But 34 | if you use the API directly, e.g. from a script or application, then you can choose to 35 | consume and use the data however you like. 36 | 37 | To run the query, click the "Run" button. A new window will open containing your results. 38 | As you work through this tutorial, you're encouraged to actually run the queries and, 39 | where suggested, customise them to explore some of the features of the language. 40 | 41 | In case you're wondering node number 1 happens to be a communications tower in 42 | Italy. I have no idea why. 43 | 44 | One important thing to note is that OpenStreetMap identifiers are not guaranteed to 45 | be stable. Someone could come along and delete a node and then it might later be recreated 46 | by the same or a different user. The node will end up with a new identifier. 47 | 48 | When you use OverpassQL you're likely to be querying information based on their location 49 | or metadata, rather than their identifier. Or, if you do, be prepared that the nodes, 50 | ways or relations you're fetching might disappear in the future. 51 | 52 | @title 00 - The Beginning 53 | */ 54 | node(1); 55 | out; 56 | -------------------------------------------------------------------------------- /tutorial/01-nodes.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query selects all of nodes that are within a bounding box. 3 | 4 | A bounding box is a rectangle that defines a geographic area. In OverpassQL a bounding box 5 | is defined by four values. The first two define the south-west corner of the box. The 6 | second pair defines its north east corner. 7 | 8 | There are two main ways to define a bounding box within an OverpassQL query. 9 | 10 | This example defines a bounding box that applies to the whole query. This is achieved using 11 | a query setting called "`bbox`". 12 | 13 | Query settings provide a way to control how the entire query runs. Query settings appear 14 | at the start of a query and are defined with square brackets: `[]`. 15 | 16 | Here we're using the `bbox` setting. As we'll see later, other settings let us 17 | choose different output formats and tweak timeouts. 18 | 19 | In the `bbox` setting we're providing the coordinates for a bounding box. 20 | These particular coordinates (`25.38653, 130.99883, -25.31478, 131.08938`) define a rectangle that 21 | includes Uluṟu. The sandstone monolith in Uluṟu-Kata Tjuta National Park, Australia. 22 | 23 | The second way to define a bounding box is as a parameter to a statement. 24 | 25 | To test this out, run the query in Overpass Turbo, then follow the instructions in the `TRYME #1` 26 | comment to see that the bounding box is applied. 27 | 28 | If you define a bounding box using a fixed set of points, then the query will 29 | only ever use that geographic area. But sometimes you want to run a query over 30 | whatever section of the map you're currently looking at. 31 | 32 | The Overpass Turbo IDE provides a third way to define a bounding box. But automatically 33 | inserting the coordinates for the current map view into your query. 34 | This is specified by including the "`{{box}}`" shortcut instead of the coordinates. Overpass Turbo will then adjust 35 | your query before its run. 36 | 37 | This won't happen if you submit a query directly to the API. Its only a feature of the IDE. But 38 | helpful when you're writing queries interactively. 39 | 40 | When should you use the different variations? 41 | 42 | * if you're using the same bounding box across your query, use a query setting. It makes the query more readable 43 | * if you need to apply a bounding box to a single statement, then define it as a filter 44 | * if you're writing a query intended to be used interactively within Overpass Turbo then use `{{bbox}}` 45 | * if you're querying the API directly, always submit queries using specific coordinates. `{{bbox}}` won't work 46 | 47 | @title 01 - Finding nodes with a bounding box 48 | */ 49 | //Defining a bounding box using query settings 50 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 51 | node; 52 | 53 | //Defining a bounding box using a statement parameter 54 | // 55 | //TRYME #1 delete or comment out the previous two statement lines 56 | //and try running the following variation instead after first removing 57 | // the two "// characters so that the statement is not treated as a comment 58 | //node(-25.38653, 130.99883, -25.31478, 131.08938); 59 | 60 | //Defining a bounding box based on the map view in Overpass Turbo 61 | // 62 | //TRYME #2. Delete or comment out the previous lines, then 63 | //try running this variation. While the other versions use a fixed box, 64 | //this version tracks you as you pan and zoom over the map. Try running it to 65 | //confirm this for yourself 66 | //node({{bbox}}); 67 | 68 | out skel; 69 | -------------------------------------------------------------------------------- /tutorial/02-node-output.osm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This query shows how to create different levels of detail in the output 4 | from your query. 5 | 6 | The `out` statement can be controlled by adding some parameters to it. These 7 | are appended to the statement. 8 | 9 | The parameters can be used to control things like: 10 | 11 | * how much information is extracted about each node (or way, or relation) 12 | * how geographic information is output 13 | * sorting and limiting results 14 | 15 | In this query we are just looking at the first of these: how to control the 16 | level of data provided for each node. 17 | 18 | The different parameters are: 19 | 20 | * `ids` - outputs only the id of nodes 21 | * `tags` - outputs only the id and tags attached to a node 22 | * `skel` - outputs only the id and geometry 23 | * `body` - output id, geometry and tags 24 | * `meta` - output id, geometry, tags plus change history 25 | 26 | Because they don't output any coordinates, the first two options will cause 27 | the IDE to only show you some XML output. It can't generate a map from a list of ids and tags. 28 | 29 | Run the query, trying different parameters. You can click around on the map to 30 | see the different levels of detail provided for the nodes that are returned. 31 | 32 | If you look closely when using the `body` and `meta` options, you'll see that 33 | the majority of nodes returned don't have any tags. 34 | 35 | This is typically because these nodes are being used as members of a way or relation. For example, to describe the location of a 36 | road or footpath. They aren't points of interest in their own right. 37 | 38 | @title 02 - Outputting data about nodes 39 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#out 40 | */ 41 | //find all the nodes in this box around Uluṟu 42 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 43 | node; 44 | 45 | //...and output data about those nodes 46 | 47 | //Outputing ids only means Overpass Turbo can't draw you a map, 48 | //you'll just get some XML output 49 | out ids; 50 | 51 | //TRYME #1 try this variant to output ids and tags 52 | //OverpassTurbo still can't draw a map, but some nodes will now 53 | //have extra information in the XML output. 54 | //out tags; 55 | 56 | //TRYME #2 try these other variants. After running each 57 | //one, click on some nodes to see how the returned data varies by 58 | //each option. Each one includes more information than the previous 59 | 60 | //ids and coordinates only 61 | //out skel; 62 | 63 | //ids, coordinates, tags, etc 64 | //out body; 65 | 66 | //same as body but with addition of information about when the node 67 | //was updated, who edited it, etc 68 | //out meta; 69 | -------------------------------------------------------------------------------- /tutorial/03-nodes-basic-filter.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query demonstrates how to filter nodes based on their tags. 3 | 4 | This is a useful and important feature. You'll be using it a lot in your queries. 5 | 6 | Tags in OpenStreetMap are used to attach information to nodes, ways and 7 | relations. There is an ever growing list of tags used to capture different 8 | types of data. 9 | 10 | Often, when we're querying the database we're not interested in all of 11 | the nodes (or ways or relations) in an area. Just those tagged as a specific type. 12 | 13 | We can specify filters in our Overpass QL queries to restrict the results to 14 | just those features that have specific tags and values. 15 | 16 | Tag filters as defined within square brackets (`[]`). This query adds a filter to 17 | the `node` statement: 18 | 19 | ``` 20 | node["name"] 21 | ``` 22 | 23 | This limits the set of returned nodes to those that have a `name` tag, regardless 24 | of its value. 25 | 26 | As we saw in the previous example, many nodes in the OpenStreetMap data are 27 | there to help define larger geospatial features. They aren't all individually 28 | points of interest. So they don't typically have any tags attached to them. 29 | 30 | When you run this query you'll see that there are now only around 30 nodes returned 31 | compared to the 4,000 or so returned in the previous examples. 32 | 33 | OpenStreetMap is a multilingual map. And some tags, like names, might have 34 | values in several different languages. 35 | 36 | The OSM data model doesn't allow tags to have multiple values, e.g. one per language. 37 | Instead we use multiple tags, which are qualified by a language code. 38 | 39 | For example, if we wanted to find nodes that have a name in Pitjantjatjara, which is 40 | the dialect spoken by the people that live around Uluṟu, then we would instead 41 | filter for a tag called `name:pjt`. 42 | 43 | Who gets to decide what goes in the default `name` tag? That's something for 44 | local mappers to discuss and agree on. See the links below for more information. 45 | 46 | @title 03 - Filtering nodes that have a tag 47 | 48 | @see https://wiki.openstreetmap.org/wiki/Key:name 49 | @see https://wiki.openstreetmap.org/wiki/Multilingual_names 50 | @see https://en.wikipedia.org/wiki/Pitjantjatjara 51 | @see https://en.wikipedia.org/wiki/Pitjantjatjara_dialect 52 | */ 53 | //find all the nodes in this box around Uluṟu 54 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 55 | 56 | //but limit to just those nodes that have a name tag 57 | node["name"]; 58 | 59 | //TRYME #1 the above two statements are equivalent to the following. 60 | //use this form if you need to query for features in several 61 | //different bounding boxes 62 | //node(-25.38653, 130.99883, -25.31478, 131.08938)["name"]; 63 | 64 | //TRYME #2 try finding just nodes that have a Pitjantjatjara name 65 | //node["name:pjt"]; 66 | 67 | //use out body to include tags in the output, so 68 | //we can inspect the results 69 | out body; 70 | -------------------------------------------------------------------------------- /tutorial/04-nodes-has-kv.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query illustrates other ways to find nodes based on their tags and the 3 | values of those tags. 4 | 5 | Tags and their values can be filtered by: 6 | 7 | * existence, e.g. whether a tag is or isn't present on the nodes 8 | * by value, e.g. whether a tag has a specific value 9 | * by regular expression matching tag values, e.g. whether the value of a tag matches a specific pattern 10 | * by regular expression matching tag names and values, e.g. where names and values match (different) patterns 11 | 12 | Together these provide a lot of flexibility. 13 | 14 | Later in the tutorial we'll learn how to do free text searches to find features 15 | of the map. But this is an IDE specific extension and not a feature of the basic 16 | Overpass API. 17 | 18 | @title 04 - Find nodes by matching tags and their values 19 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_tag_.28has-kv.29 20 | @see https://en.wikipedia.org/wiki/Regular_expression#POSIX_basic_and_extended 21 | */ 22 | //find all the nodes in this box around Uluṟu 23 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 24 | 25 | //EXISTENCE CHECKS 26 | 27 | //but limit to just those nodes that DO have a name tag 28 | node["name"]; 29 | 30 | //TRYME nodes that DON'T have a name tag 31 | //node[!"name"]; 32 | 33 | //BY VALUE 34 | 35 | //TRYME nodes that have the name 'Uluṟu' in Pitjantjatjara 36 | //node["name:pjt"="Uluṟu"]; 37 | 38 | //REGULAR EXPRESSIONS, matching values 39 | 40 | //TRYME nodes whose name ends in 'Viewing' 41 | //node["name"~"Viewing$"]; 42 | 43 | //TRYME nodes whose name starts in 'Viewing' 44 | //node["name"~"^Viewing"]; 45 | 46 | //TRYME nodes whose name includes 'Viewing' 47 | //node["name"~"Viewing"]; 48 | 49 | //TRYME nodes who name includes 'Viewing', ignoring case 50 | //node["name"~"Viewing", i]; 51 | 52 | //REGULAR EXPRESSIONS, matching tag names 53 | //in this case any node with a name, or language code qualified name 54 | //node[~"^name(:.*)?$"~"."]; 55 | 56 | out body; 57 | -------------------------------------------------------------------------------- /tutorial/05-nodes-combined-filter.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Filters applied to queries for nodes, ways and relations can be combined to 3 | build up more complex expressions. 4 | 5 | Any number of filters can be appended to query statements. They must all apply for 6 | a feature to be included in the results. 7 | 8 | In this example we combine a key-value match with a regular expression to 9 | match nodes that are tagged as cave entrances and whose name starts with 10 | "Kulpi" in Pitjantjatjara. 11 | 12 | The comments show a variation that illustrates querying for nodes that have a 13 | `name` tag but don't also have a name specified in Pitjantjatjara. 14 | 15 | @title 05 - Find nodes by applying multiple filters 16 | @see https://wiki.openstreetmap.org/wiki/Key:natural 17 | @see https://parksaustralia.gov.au/uluru/do/rock-art/kulpi-mutitjulu/ 18 | @see https://parksaustralia.gov.au/uluru/do/rock-art/kulpi-nyiinkaku/ 19 | */ 20 | //find all the nodes in this box around Uluṟu 21 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 22 | node["natural"="cave_entrance"]["name:pjt"~"^Kulpi"]; 23 | 24 | //TRYME nodes that have a name tag, but which don't have a Pitjantjatjara name tag 25 | //node["name"][!"name:pjt"]; 26 | 27 | out meta; 28 | -------------------------------------------------------------------------------- /tutorial/06-nodes-union.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Sometimes when we are querying for data, we want to build up a larger collection of features 3 | that we are interested in. For example, a collection of different types of road, amenities or natural features. 4 | 5 | Rather than do this in multiple separate queries, we can extract that collection using a single query, using a union. 6 | 7 | In OverpassQL we create a union by specifying a block using curved brackets (`()`). 8 | Within that block we can include all of the queries necessary to build our collection 9 | of results. 10 | 11 | The general syntax is: 12 | 13 | ``` 14 | ( 15 | statement1; 16 | statement2; 17 | ) 18 | ``` 19 | 20 | For example this query will return all those nodes that have been tagged with the 21 | `tourism` tag AND those tagged as a cave entrance. 22 | 23 | We use separate individual `node` statements to build up the collection we want. 24 | 25 | The `out` statement will then output the combined results. 26 | 27 | This type of query is useful in any context. But its particularly useful for querying the OpenStreetMap database because: 28 | 29 | * we are often extracting different types of features, e.g. nodes, ways and relations, and its easier to get these in one pass 30 | * nodes (and ways, and relations) can be tagged in different ways, so we often need to specify variations of tags to collect the features of interest 31 | * by building up larger sets, we can do more complex queries that involve set operations 32 | 33 | We'll cover set operations and variables in a later example. 34 | 35 | @title 06 - Extracting multiple sets of nodes 36 | */ 37 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 38 | ( 39 | node["tourism"]; 40 | node["natural"="cave_entrance"]; 41 | ); 42 | out meta; 43 | -------------------------------------------------------------------------------- /tutorial/07-nodes-differences.osm: -------------------------------------------------------------------------------- 1 | /* 2 | The previous example demonstrated how to create a union from multiple 3 | `node` queries. 4 | 5 | The sets of results returned by each query statement are merged to produce 6 | the output. 7 | 8 | We can also calculate the difference between two sets of results. 9 | 10 | We do this by using the minus operator. The general syntax is: 11 | 12 | ``` 13 | ( statement1; - statement2; ) 14 | ``` 15 | 16 | The result will be those nodes (or ways or relations) returned by 17 | `statement1` that weren't returned by `statement2`. 18 | 19 | This query finds all nodes that are tagged as tourist areas and are not also 20 | tagged as caves. 21 | 22 | We can achieve the same thing using a simple tag filter, but this helps to 23 | illustrate the basic syntax. 24 | 25 | @title 07 - Calculating differences between results 26 | */ 27 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 28 | ( 29 | node["tourism"]; 30 | - 31 | node["natural"="cave_entrance"]; 32 | ); 33 | out body; 34 | -------------------------------------------------------------------------------- /tutorial/08-nodes-json-output.osm: -------------------------------------------------------------------------------- 1 | /* 2 | When you're viewing results in the Overpass Turbo IDE it'll show your results on a map. 3 | Or at least it will if you have used an `out` option that produces some geometry. 4 | 5 | But you can always see the raw data by clicking on the "Data" tab. 6 | 7 | By default the Overpass API returns XML. But it can also produce JSON output. 8 | 9 | To request that you need to use the `out` query setting. Confusingly this has the 10 | same name as the keyword used to generate results in different level of details, 11 | but they perform different roles and appear in different parts of a query. 12 | 13 | * `[out:xxx]` is a query setting that specifies the format of the data. It appears at the start of a query 14 | * `out` is a statement that is used to control how much data is included in the results. It appears in the body of a query. 15 | 16 | The JSON output is a custom format. It's not GeoJSON but isn't hard to convert to that 17 | format. 18 | 19 | If you're using the Overpass Turbo application then the "Export" menu offers the option to 20 | do this conversion for you. This is downloaded directly from the application. You can't 21 | request GeoJSON directly from the API. 22 | 23 | @title 08 - Generating JSON output 24 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#Output_Format_.28out:.29 25 | @see http://overpass-api.de/output_formats.html#xml 26 | @see https://wiki.openstreetmap.org/wiki/OSM_XML 27 | @see http://overpass-api.de/output_formats.html#json 28 | */ 29 | //NOTE: no semi-colon after the out settings. The settings are considered to be 30 | //a single statement. 31 | [out:json] 32 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 33 | node["name"]; 34 | out body; 35 | -------------------------------------------------------------------------------- /tutorial/09-nodes-csv-output.osm: -------------------------------------------------------------------------------- 1 | /* 2 | OverpassQL can also be used to generate simple CSV exports. 3 | 4 | This is achieved by using the `[out:csv]` query setting. 5 | 6 | In order for the API to know how to construct the CSV output you must provide 7 | a specification of what fields (columns) to include. These fields are either: 8 | 9 | * a special field name, which is predefined by the API, e.g. `::id` 10 | * or the name of a tag 11 | 12 | The special field names include: 13 | 14 | * `::id` - the database id of the object 15 | * `::type` - its type, e.g. node, way or relation 16 | * `::lat` - its latitude 17 | * `::lon` - its longitude 18 | 19 | The list of columns to include in the output are specified as parameters in the query setting 20 | statement. 21 | 22 | Other parameters allow you to customise whether a header line is included in the CSV file and 23 | choose the column separator. The defaults are to include a header and produce a tab delimited 24 | file. 25 | 26 | The general syntax for the `out:csv` setting is: 27 | 28 | ``` 29 | [out:csv (columns; header; col-separator)] 30 | ``` 31 | 32 | Where: 33 | 34 | * `columns` is a comma separated list of names 35 | * `header` is either `true` or `false` 36 | * `col-separator` is the desired separator provided as a string. 37 | 38 | This query generates a simple comma-separated table containing the `id`, coordinates 39 | and names of caves within the bounding box. But some other variations are also provided for 40 | you to try out. 41 | 42 | If you want to include tags in your CSV output, then the `out` keyword of your 43 | query **must** generate tags. So use `out body` or `out meta`. 44 | 45 | Also note that when you're including latitude (`::lat`) and longitude (`::lon`) 46 | columns then for nodes you'll get their original coordinates. But ways and relations are 47 | more complex spatial objects. They aren't defined by a single point. 48 | 49 | You can use the `out` keyword to automatically generate a representative location (a "centroid") 50 | for those types of feature. Specifying `out body center` will do the trick. This will calculate 51 | a centroid for any way or relation in your results. 52 | 53 | **Tip**: when generating CSV output, if there is a query error or timeout then you will 54 | get empty results. I'd recommend writing and testing your basic query first so you're 55 | sure it's working. And then customise it further to generate the desired CSV output. 56 | 57 | @title 09 - Generating CSV output 58 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#CSV_output_mode 59 | */ 60 | //Comma separated table of id, coordinates and names 61 | [out:csv(::id, ::lat, ::lon, name; true; ",")]; 62 | 63 | //TRYME #1 include node type 64 | //[out:csv(::id, ::lat, ::lon, ::type, name; true; ",")]; 65 | 66 | //TRYME #1 pipe delimited, no header 67 | //[out:csv(::id, ::lat, ::lon, ::type, name; false; "|")]; 68 | 69 | //find nodes tagged as caves 70 | node(-25.38653, 130.99883, -25.31478, 131.08938)["natural"="cave_entrance"]; 71 | 72 | //include tags in output, so we can have them in our CSV output 73 | out body; 74 | -------------------------------------------------------------------------------- /tutorial/10-the-default-set.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Overpass queries consist of statements that query the OSM database to build 3 | up a set of results which can be serialised into different output formats. 4 | 5 | That set of results has a name. It's called `_`(underscore). 6 | 7 | All of the queries we've written so far have implicitly worked with this result 8 | set. 9 | 10 | Our `node` queries have added results to the `_` set and the `out` statements 11 | have used the default set to produce our output. 12 | 13 | The query below makes this use of the default set more obvious by explicitly 14 | using it in the individual statements. 15 | 16 | The results of a statement can be written to a named set using the `->` operator. 17 | 18 | As we'll see in the following examples it is possible to create, manipulate 19 | and produce output from multiple named sets of results. 20 | 21 | @title 10 - The default set 22 | */ 23 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 24 | 25 | //find nodes within out bounding box that have a name 26 | //and write the result to the default set 27 | node["name"]->._; 28 | 29 | //from the default set output just the id and coordinates of the result 30 | ._ out skel; 31 | -------------------------------------------------------------------------------- /tutorial/11-query-a-set.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query demonstrates syntax for querying and serialising 3 | the contents of a named set. 4 | 5 | Rather than work with the default set, this query only uses named sets. This 6 | illustrates how every statement works with data from an input set and stores its 7 | results in an output set. 8 | 9 | First we find nodes that have a name and store them in a set of results 10 | called "named_nodes". 11 | 12 | Set names can include letters, digits and the underscore character. But names 13 | must not start with a digit. 14 | 15 | Secondly, we then query within that first set of results, filtering to just those 16 | nodes that are tagged as a cave entrance. 17 | 18 | For node queries we append the name of the set to the keyword using a dotted syntax: 19 | 20 | ``` 21 | node.named_nodes 22 | ``` 23 | 24 | This means the statement will use that set rather than the OSM database. 25 | 26 | So `node.named_nodes` means "Query nodes found in the set 'named_nodes'". The 27 | nodes are then filtered based on the value of their `natural` tag. 28 | 29 | The results of that query are written to another named set. This time called 30 | `caves`. 31 | 32 | Finally, we output the contents of the `caves` set. 33 | 34 | This query is a little artificial as we can achieve the same thing by querying 35 | the database directly. But in more complex queries you may be working with 36 | multiple sets of results that you want to filter, explore and output in different 37 | ways. 38 | 39 | We can also output results from different sets through repeated uses of the 40 | `out` keyword that reference different sets. 41 | 42 | Every OverpassQL query command can work with named sets as well as the default 43 | "`_`" set. They can also store their results in named sets. This provides a 44 | great deal of flexibility. 45 | 46 | @title 11 - Querying a set 47 | */ 48 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 49 | 50 | //find all nodes with a name, storing results in a set called "named_nodes" 51 | node["name"]->.named_nodes; 52 | 53 | //extract from the set "named_nodes", just those with 54 | node.named_nodes["natural"="cave_entrance"]->.caves; 55 | 56 | .caves out body; 57 | -------------------------------------------------------------------------------- /tutorial/12-radius-search.osm: -------------------------------------------------------------------------------- 1 | /* 2 | OverpassQL allows us to perform some basic spatial queries. 3 | 4 | We've already explored various ways to query for nodes within a bounding box. 5 | 6 | We can also search for nodes or other features that can be found within a circular 7 | area using the `around` filter. 8 | 9 | This filter uses curved brackets (`()`). Only tag filters use square brackets (`[]`). 10 | 11 | The simplest form of this filter accepts a distance (in meters) and a latitude and 12 | longitude. This point and distance describe the centre of a circle and its radius. 13 | 14 | The results are then filtered to features that are within that search area. 15 | 16 | This example query finds nodes tagged as caves that are within 800m of the peak 17 | of Uluṟu. There is a single result, which is a cave called Tjilpi Pampa Kulpi. 18 | 19 | Notice that we don't define a bounding box for this particular query. Our area 20 | of interest is specified by the `around` filter. 21 | 22 | There are more complex ways that we can use the `around` filter. 23 | 24 | Instead of searching within a circle, we can instead query for nodes that can be 25 | found near to a line. To use this variant, we would need to specify multiple 26 | latitude/longitude pairs that define the line we are interested in. An example is 27 | shown in the query for you to try. 28 | 29 | An even more useful version of `around` is shown in the next example. 30 | 31 | @title 12 - Searching within a radius using around 32 | */ 33 | node(around:800.00,-25.344857,131.0325171)["natural"="cave_entrance"]; 34 | 35 | //TRYME, find caves within 100m of a line defined by two coordinates 36 | node(around:100.00,-25.340861, 131.0252552,-25.3400707, 131.0275297)["natural"="cave_entrance"]; 37 | 38 | out body; 39 | -------------------------------------------------------------------------------- /tutorial/13-around-with-set.osm: -------------------------------------------------------------------------------- 1 | /* 2 | The `around` filter can be used to find features that are near to a previously 3 | extracted set of results. 4 | 5 | This, more powerful, use of the filter is illustrated in this query. 6 | 7 | The query does two things. 8 | 9 | Firstly it searches within the bounding box to find all nodes that are 10 | tagged as peaks. These nodes will be automatically stored in the default set ("`_`"). 11 | 12 | The second part of the query then filters to just those nodes that are tagged as 13 | caves AND are within 850m of one of the previously found results. 14 | 15 | In this case there is only a single peak within our bounding box (the summit of 16 | Uluṟu), so the query returns just those caves that are within 850m. 17 | 18 | If the `around` filter isn't provided with coordinates, or a set of coordinates, 19 | then it uses the default set ("`_`") as the basis for its search. 20 | 21 | As with other query statements, you can also specify the set to use. The comments 22 | in the query indicate an alternative way to achieve the same result but using named sets. 23 | 24 | My suggestion is to always used named sets to make your queries more readable. 25 | 26 | This way of using `around` is much more powerful than specifying a fixed radius 27 | or line. We can instead do more complex queries such as finding amenities that 28 | are near to bus stops or a road. 29 | 30 | When experimenting with this query try using the `out count` variation. This 31 | produces a count of the nodes, rather than their coordinates and tags. Useful 32 | if you just want to do some quick analysis or collect some figures. 33 | 34 | **Tip**: If you try `out count`, Overpass Turbo may warn you that there are 35 | no results it can display on the map. Just look at the data tab instead. 36 | 37 | @title 13 - Using around to filter against a set of results 38 | */ 39 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 40 | node["natural"="peak"]; 41 | node(around:850.00)["natural"="cave_entrance"]; 42 | 43 | //TRYME #1 this produces the same output, but shows how to 44 | //make around use a named set of results, instead of the default set 45 | //node["natural"="peak"]->.peaks; 46 | //node(around.peaks:850.00)["natural"="cave_entrance"]; 47 | 48 | out body; 49 | 50 | //TRYME #2. Try producing a count of the results instead of a list of nodes 51 | //out count; 52 | -------------------------------------------------------------------------------- /tutorial/14-searching-by-polygon.osm: -------------------------------------------------------------------------------- 1 | /* 2 | OverpassQL supports searching for features within a polygon defined by a collection of 3 | points. 4 | 5 | The `poly` filter accepts a single parameter. This must be a string value that 6 | contains an even number of latitude and longitude pairs. Collectively these 7 | coordinates should define a closed shape on the map. 8 | 9 | This polygon is then used as the boundary for the query. 10 | 11 | This query extracts nodes that can be found within a polygon that covers 12 | an area to the west of Uluṟu. 13 | 14 | There isn't a default bounding box defined in this query, as our area of 15 | interest is fully described by the `poly` filter. 16 | 17 | Note there's some quirks around syntax here which make `poly` slightly different to 18 | `around`: 19 | 20 | * the parameter MUST be provided as a quoted string. 21 | * the coordinate values MUST be separated by spaces and not commas. 22 | 23 | The syntax for the `around` filter is different. 24 | 25 | Unfortunately, unlike `around`, the `poly` filter doesn't support querying based 26 | on a polygon that was found by a previously extracted set of nodes. 27 | 28 | So you can't, for example, extract the polygon describing a closed way 29 | stored in OpenStreetMap and then search within it. This feels like an oversight, but 30 | we'll see how to do this type of query later in the tutorial. 31 | 32 | **Tip**: the more complex your polygon, the slower the search. Simplify the boundary 33 | to improve performance. 34 | 35 | @title 14 - Searching by polygon 36 | */ 37 | node(poly:"-25.336204100149033 131.0238147136019 -25.341828144950995 131.02072480881674 -25.341944501738343 131.02754834855062"); 38 | out body; 39 | -------------------------------------------------------------------------------- /tutorial/15-ways.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Ways are used to describe lines and polygons in the OpenStreetMap database. 3 | 4 | Ways are used for roads, paths and the boundaries of buildings and parks. 5 | 6 | To query for ways we just use the `way` keyword instead of the `node` keyword. 7 | 8 | For example, this query extracts all the ways in our bounding box. 9 | 10 | It will return the data about those ways. This includes their tags and references to the individual nodes that describe them. 11 | 12 | But the IDE won't be able to generate a map for you. And will probably give you a warning about that. 13 | 14 | This is because ways don't have their own geometry. Instead they are associated with a collection of nodes that 15 | mark out the shape of the way. 16 | 17 | You can view the tags for these ways and the ids of the nodes that are members of 18 | them via the "Data" tab in the IDE. 19 | 20 | In the next query we'll learn how to also extract the nodes for these ways. 21 | 22 | @title 15 - Finding ways 23 | @see https://wiki.openstreetmap.org/wiki/Way 24 | */ 25 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 26 | way; 27 | out body; 28 | -------------------------------------------------------------------------------- /tutorial/16-ways-and-their-nodes.osm: -------------------------------------------------------------------------------- 1 | /* 2 | To create maps for ways, we need to also extract the nodes that describe 3 | their outline. 4 | 5 | In OverpassQL we do this using the "recurse down" statement "`>`". 6 | 7 | This statement takes an input set of elements and then finds any 8 | node (or way, or relation) that are a member of those elements. 9 | 10 | The members of a way are its nodes. 11 | 12 | The members of a relation would consist of the nodes and ways that it contains. 13 | 14 | Nodes don't have members so these are ignored when performing a traversal. 15 | 16 | This query extracts all ways within our bounding box. It then uses a 17 | traversal query to also find the members of those nodes. 18 | 19 | We then use a union of those two queries to produce output that includes the data 20 | about both the way and its nodes. 21 | 22 | The recurse operator implicitly uses the default set (`_`) as its input. Without 23 | that bit of context, the syntax can seem a bit arcane! It took me a while to understand 24 | what it is doing. 25 | 26 | The `>` query is very commonly used in queries, as we need it whenever we want 27 | geometry for ways and relations. There is also a version that will traverse all 28 | the way from relations down to nodes: `>>`. 29 | 30 | If we didn't use the `()` block and just queried for ways and nodes in 31 | turn, then the output would _only_ contain data about the nodes. This is because 32 | the `>` query will overwrite the contents of the default set, so we'd lose the 33 | results of our `way` query. 34 | 35 | Always use a union block when performing traversals unless you really want to 36 | ignore the parent features. Many examples of using OverpassQL just include the 37 | `()` block by default, because it's so important for most queries. 38 | 39 | @title 16 - Ways and their nodes 40 | */ 41 | //define the bounding box for our search 42 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 43 | 44 | //this block creates a collection of ways and their nodes 45 | ( 46 | //find the ways 47 | way; 48 | 49 | //find the nodes that are members of those ways 50 | >; 51 | ); 52 | 53 | //output the collection of nodes and ways 54 | out body; 55 | -------------------------------------------------------------------------------- /tutorial/17-ways-and-their-tags.osm: -------------------------------------------------------------------------------- 1 | /* 2 | When querying for ways we can apply everything we've learned from querying 3 | for nodes. 4 | 5 | That includes filtering them based on their tags. Or using them to search 6 | nearby on the map. 7 | 8 | The query below selects just those ways in our bounding box that have been 9 | tagged as a tourist attraction. As the time of writing, that results in a 10 | single way which marks out the boundary of Uluṟu. 11 | 12 | See the query comments for other variations to try, including finding 13 | highways, footpaths and amenities near to paths. 14 | 15 | @title 17 - Ways and their tags 16 | @see https://wiki.openstreetmap.org/wiki/Key:tourism 17 | @see https://wiki.openstreetmap.org/wiki/Key:highway 18 | @see https://wiki.openstreetmap.org/wiki/Key:foot 19 | @see https://wiki.openstreetmap.org/wiki/Key:disused 20 | */ 21 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 22 | ( 23 | way["tourism"="attraction"]; 24 | 25 | //TRYME #1, ways that are tagged as highways. This includes roads and paths 26 | //way["highway"]; 27 | 28 | //TRYME #2, ways that are tagged as paths 29 | //way["highway"="path"]; 30 | 31 | //TRYME #3, ways that are marked as designated pedestrian access 32 | //way["foot"="designated"]; 33 | 34 | //TRYME #4, ways that are tagged as disused highways 35 | //way["disused:highway"="path"]; 36 | 37 | >; 38 | ); 39 | out body; 40 | -------------------------------------------------------------------------------- /tutorial/18-nodes-and-ways.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Now that we can query for both nodes and ways we can do more complex queries. 3 | 4 | Here is an example that finds ways within our bounding box. It then uses an 5 | `around` filter to query for nodes tagged as `amenity` that are within 100 meters 6 | of those ways. 7 | 8 | Remember that the `around` filter will read from the default set if a named 9 | set is not specified. So the node query is implicitly filtering based on the results 10 | found in the `way` query. Both queries are limited by the bounding box set for the whole query. 11 | 12 | @title 18 - Combining node and way queries 13 | */ 14 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 15 | way; 16 | node(around:100)["amenity"]; 17 | out body; 18 | -------------------------------------------------------------------------------- /tutorial/19-find-ways-from-nodes.osm: -------------------------------------------------------------------------------- 1 | /* 2 | We previously looked at how to use the `>` operator to find members of ways. 3 | 4 | But we can also go the opposite way and find ways from their nodes. We can do 5 | this using the "recurse up" statement (`<`) which, as the arrow might suggest, goes in the 6 | opposite direction. 7 | 8 | This query finds all of the nodes in our bounding box and also the ways of which 9 | they are members. 10 | 11 | There's also a `<<` statement that will traverse from nodes all the way up to 12 | the relations that contain them. 13 | 14 | @title 19 - Finding ways from their nodes 15 | */ 16 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 17 | 18 | //this block creates a collection of ways and their nodes 19 | ( 20 | 21 | //find the nodes 22 | node; 23 | 24 | //find the way of which they are members 25 | <; 26 | ); 27 | 28 | //output the collection of nodes and ways 29 | out body; 30 | -------------------------------------------------------------------------------- /tutorial/20-relations.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Having looked at nodes and ways, the final part of the OSM data model we have 3 | to explore are relations. 4 | 5 | Relations are collections of nodes and ways. They describe logical groupings of 6 | objects that go beyond their basic spatial relationship. For example a relation 7 | can be used to describe: 8 | 9 | * a bus route, which connects a set of bus stop (nodes) and ways (the route) 10 | * an administrative boundary 11 | * a multipolygon, such as a collection of buildings that represent a single location 12 | 13 | We query for relations using the `relation` keyword, or its synonym (`rel`). 14 | 15 | We can apply filters based on tags, perform spatial queries as standard. And similar 16 | to ways we will need to use the recursion operators (`>`, `>>`) to find their 17 | geometries. 18 | 19 | This query finds administrative boundaries within our bounding box. 20 | 21 | @title 20 - Finding relations 22 | @see https://wiki.openstreetmap.org/wiki/Relation 23 | */ 24 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 25 | relation["boundary"="administrative"]; 26 | out body; 27 | -------------------------------------------------------------------------------- /tutorial/21-type-agnostic-queries.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Objects in the OpenStreetMap database can be represented in different ways. 3 | 4 | For example a shop might initially be added as a node (a point location) 5 | and later changed to be represented by a way. This might happen if a mapper adds 6 | an outline for the building in which the business operates. 7 | 8 | Sometimes we want to query using `node`, `way` or `relation` because we know what 9 | data we want. But how do we find things that might be represented as any of these 10 | types? 11 | 12 | One approach is to union the results of multiple queries that fetch all the 13 | possible variations, e.g: 14 | 15 | ``` 16 | ( 17 | node["amenity"]; 18 | way["amenity"]; 19 | rel["amenity"]; 20 | ); 21 | ``` 22 | 23 | But this is repetitive. There are variations of the `node`, `way` and `relation` 24 | queries we can use that are more succinct: 25 | 26 | * `nw` - to find nodes and ways 27 | * `nr` - to find nodes and relations 28 | * `wr` - to find ways and relations 29 | * `nwr` - to find nodes, ways and relations 30 | 31 | We can apply filters to these statements just like their single type equivalents. 32 | 33 | This is a much more succinct way of finding objects of various types. These 34 | are fairly recent additions to the language, so you will still encounter many 35 | queries that build up results by querying for each type in turn (see the comments 36 | in the example below). 37 | 38 | This example extracts all of the nodes, ways and relations in our bounding box. 39 | 40 | @title 21 - Type agnostic queries (nwr) 41 | */ 42 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 43 | nwr; 44 | 45 | //this is equivalent to the following three lines: 46 | //node; 47 | //way; 48 | //relation; 49 | 50 | out body; 51 | -------------------------------------------------------------------------------- /tutorial/22-areas.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query finds all natural rock formations within Uluṟu-Kata Tjuta National Park. 3 | 4 | The results include Uluṟu, Kata Tjuta, Taputji and Mala Kata. 5 | 6 | Kata Tjuta is a more complex rock formation and is represented as a relation in 7 | the OSM database. So if we had used only a `way` query then it wouldn't be present 8 | in the results. The `wr` query lets us do a type agostic query to find the areas 9 | of interest. 10 | 11 | So far we've written queries to find nodes, ways and relations. But in this query 12 | we are using a new statement: `area`. 13 | 14 | Areas are interesting in that they are not formally part of the OSM data model. 15 | They are features which have been automatically added to the databases that power the Overpass API. This means that 16 | they can be queried and manipulated via the API, but they're not something you can edit. 17 | 18 | Areas are automatically created for a range of different types of ways and relations, including: 19 | 20 | * any relation with a `type` of `multipolygon` and a `name` 21 | * any relation with a `type` of `boundary` and a `name` 22 | * any relation that has an `admin_level` and `name` attribute 23 | * any relation with a `postal_code` or `addr:postcode` 24 | * a wide range of different named ways including buildings, highways, natural features, leisure areas, places, historic and tourism areas 25 | 26 | The complete list is evolving over time. 27 | 28 | Areas then are a set of features that are derived from a subset of the ways and 29 | relations that exist in the wider database. 30 | 31 | From a query perspective, you can think of them like other elements and find them 32 | using the standard range of filters. 33 | 34 | For example in this query we're finding an area based on its name. 35 | 36 | ``` 37 | area["name"="Uluru-Kata Tjuta National Park"] 38 | ``` 39 | 40 | The advantage of using areas rather the original ways and relations is that the API and 41 | query language provides some additional functionality for working with them. 42 | 43 | For example in this query we're using an `area` filter, like this: 44 | 45 | ``` 46 | way(area); 47 | ``` 48 | 49 | The `area` filter restricts the ways (or nodes, or relations) we're interested in 50 | to just those that within an area we've already found. This type of spatial query 51 | isn't normally available for ways and relations. I presume this is to limit the amount 52 | of indexing required to support this type of query. 53 | 54 | The `area` query and the `area` filter both work with named sets. By default they work 55 | with the default set (`_`). And this is what the example query uses. 56 | 57 | But an alternate way to write this example is to explicitly store the area we're 58 | interested in a named set. I find this a bit clearer in practice. 59 | 60 | Here's how this would look, using a named set called `ourArea`: 61 | 62 | ``` 63 | area["name"="Uluru-Kata Tjuta National Park"]->.ourArea; 64 | ( 65 | way(area.ourArea)["natural"="bare_rock"]; 66 | >; 67 | ); 68 | ``` 69 | 70 | If we wanted to instead find nodes or relations then we could use either of the 71 | following: 72 | 73 | ``` 74 | node(area.ourArea); 75 | relation(area.ourArea); 76 | ``` 77 | 78 | @see https://wiki.openstreetmap.org/wiki/Overpass_API/Areas 79 | @see https://github.com/drolbr/Overpass-API/blob/master/src/rules/areas.osm3s 80 | @see https://en.wikipedia.org/wiki/Kata_Tjuta 81 | @see http://www.indigenousaustralia.info/the-dreaming/rock-legends/taputji.html 82 | @title 22 - Areas 83 | */ 84 | //find any area with this name 85 | area["name"="Uluru-Kata Tjuta National Park"]; 86 | ( 87 | //find any ways and relations that are WITHIN that area, filtering them by their tag 88 | wr(area)["natural"="bare_rock"]; 89 | >; 90 | ); 91 | out body; 92 | -------------------------------------------------------------------------------- /tutorial/23-areas-from-features.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Sometimes we want to find the area that encloses some features of interest. 3 | For example, finding the administrative area for a firestation. Or the park that 4 | contains a play area. 5 | 6 | This query demonstrates how to find the area that encloses a point using the 7 | `is_in` statement. 8 | 9 | The `is_in` statement allows us to find areas based on some previously found 10 | nodes, ways or relations.. 11 | 12 | The first part of our query finds the area that contains the summit of Uluṟu: 13 | 14 | ``` 15 | node["name:pjt"="Uluṟu"]->.summit; 16 | .summit is_in ->.someArea; 17 | ``` 18 | 19 | A named result set (`summit`) is used here to make things clearer. We first store 20 | the node(s) we found in a variable called `summit`. 21 | 22 | Then we use `is_in` to find which areas contain those elements. This will be ALL 23 | the areas that cover that point. Not just the boundary of Uluṟu, but also 24 | that of the Uluṟu-Kata Tjuṯa National Park, Petermann, the Macdonnell Region and so 25 | on all the way up to Australia. 26 | 27 | `is_in` returns the full spatial coverage starting from one or more features. 28 | 29 | The Overpass API will give us the tags associated with areas, but not their geometry. 30 | 31 | If we want that, then we need to find the original ways or relations from which 32 | the area was created. 33 | 34 | We do that by applying the `pivot` filter. This filter finds the corresponding OSM 35 | database feature for an area (or areas) in our result set. 36 | 37 | In our example query we find the `way` that corresponds to the area surrounding 38 | the summit of Uluṟu like this: 39 | 40 | ``` 41 | way(pivot.someArea); 42 | ``` 43 | 44 | If we'd instead wanted to find a relation, then we would have used: 45 | 46 | ``` 47 | relation(pivot.someArea); 48 | ``` 49 | 50 | @title 23 - Finding the areas enclosing a feature 51 | */ 52 | ( 53 | //find the node named Uluṟu. Save it in a named set called "summit" 54 | node["name:pjt"="Uluṟu"]->.summit; 55 | 56 | //for the node(s) in the named set called "summit" find the areas they are in 57 | //save the results in another named set called "someArea" 58 | .summit is_in ->.someArea; 59 | 60 | //TRYME 2 try commenting out these two lines and looking in the 61 | //"Data" tab to see just the area data 62 | way(pivot.someArea); 63 | >; 64 | ); 65 | out body; 66 | -------------------------------------------------------------------------------- /tutorial/24-mapToArea.osm: -------------------------------------------------------------------------------- 1 | /* 2 | The previous example illustrated how to turn an area into a way, so that we 3 | can plot it on the map. For that we used the `pivot` filter. 4 | 5 | Sometimes it can be helpful to go the other way and find the area that 6 | corresponds to a way or relation. To do that we use the `map_to_area` statement. 7 | 8 | This allows us to then do spatial queries using that area, which we can't do with 9 | the original way or relation. 10 | 11 | For example in this query we find the OSM relation tagged as Mutitjulu. 12 | 13 | This is intended to represent an administrative boundary for the Mutitjulu community 14 | that is found just east of Uluṟu. This is stored in a temporary named set. 15 | 16 | We then use the `map_to_area` statement to find the area corresponding to 17 | that relation. This is saved in a variable called `mutitjulu`. 18 | 19 | We then do a couple of type agnostic queries to find node, ways and relations 20 | that are tagged as buildings or leisure areas. 21 | 22 | @title 24 - Find the area derived from a feature 23 | @see https://en.wikipedia.org/wiki/Mutitjulu 24 | */ 25 | [bbox:-25.38653, 130.99883, -25.31478, 131.08938]; 26 | ( 27 | relation["name"="Mutitjulu"] ->.rel; 28 | .rel map_to_area ->.mutitjulu; 29 | nwr["leisure"](area.mutitjulu); 30 | >; 31 | nwr["building"](area.mutitjulu); 32 | >; 33 | ); 34 | out body; 35 | -------------------------------------------------------------------------------- /tutorial/25-areas-via-nominatim.osm: -------------------------------------------------------------------------------- 1 | /* 2 | This query shows another way to search for areas to help filter queries. 3 | 4 | The Overpass Turbo IDE provides several [extensions](../syntax-reference.html#overpass-turbo-extensions) to the core OverpassQL language. 5 | 6 | We met one of those much earlier in the tutorial. We used `{{bbox}}` to 7 | automatically define a bounding box based on the current view of the map in the IDE. 8 | 9 | Another useful extension is `geocodeArea`, which is demonstrated in this query. 10 | 11 | The extension accepts a search parameter which is used to do a free-text 12 | search using the Nominatim API to find the first matching area. 13 | 14 | This can be a more flexible way to match areas. Otherwise we are limited to doing 15 | matching of tag values using regular expressions. 16 | 17 | Just remember this is an Overpass Turbo only feature. If you want to achieve a similar 18 | effect in an application you'll need to query both APIs. 19 | 20 | @see https://wiki.openstreetmap.org/wiki/Nominatim 21 | @title 25 - Areas via Nominatim search 22 | */ 23 | {{geocodeArea:"Uluṟu-Kata Tjuta National Park"}}->.searchArea; 24 | ( 25 | //find all nodes tagged as caves within the area we found 26 | node["natural"="cave_entrance"](area.searchArea); 27 | ); 28 | out body; 29 | -------------------------------------------------------------------------------- /tutorial/26-timeouts-and-endpoints.osm: -------------------------------------------------------------------------------- 1 | /* 2 | Like any open, public API the Overpass API imposes both time and memory limits 3 | on queries. 4 | 5 | The default time out value is 180 seconds. Which is quite a long time, although in 6 | practice your query might also be rejected because of server load or because it hits 7 | memory limits. 8 | 9 | While the default timeout is quite generous, sometimes you just need a little bit 10 | more time. The `timeout` query parameter can be used to request a longer timeout for your 11 | query. 12 | 13 | Use it to specify a timeout value in seconds. The below takes our earlier CSV output 14 | example and sets a timeout of 60 seconds. 15 | 16 | One other option available is to switch to using a different Overpass API endpoint. 17 | There are a number of public Overpass instances. But there are others which 18 | are listed on the OSM wiki. 19 | 20 | When you're using Overpass Turbo your queries will be load-balanced across two of 21 | these endpoints. 22 | 23 | Be sure to check the details around terms of use before putting any load on them. 24 | And be aware that they don't store exactly the same data. Some don't include "attic data" 25 | which includes data about historical changes to the OSM database. 26 | 27 | If you're querying the APIs directly, then you can just point your code at the right 28 | URL. But if you're using Overpass Turbo then you'll need to include a special instruction 29 | as the first line of your query. 30 | 31 | To use the Kumi Systems Overpass instance, use the following: 32 | 33 | ``` 34 | {{data:overpass,server=https://overpass.kumi.systems/api/}} 35 | ``` 36 | 37 | @see https://wiki.openstreetmap.org/wiki/Overpass_API#Public_Overpass_API_instances 38 | @see https://overpass.kumi.systems/ 39 | @title 26 - Timeouts and endpoints 40 | */ 41 | [out:csv(::id, ::lat, ::lon, name; true; ",")][timeout:60]; 42 | node(-25.38653, 130.99883, -25.31478, 131.08938)["natural"="cave_entrance"]; 43 | out body; 44 | -------------------------------------------------------------------------------- /tutorial/overview.md: -------------------------------------------------------------------------------- 1 | This is a collection of queries that provides a simple tutorial that introduces 2 | the core features and syntax of the Overpass QL query language. 3 | 4 | Each of the queries introduces a specific feature of the language, starting 5 | from querying for simple points of interest through to more complex spatial 6 | queries. 7 | 8 | By the end of the tutorial you will learn: 9 | 10 | * some basics of the OpenStreetMap data model 11 | * how to write queries to extract nodes, ways and relations from the OSM database using a variety of different methods 12 | * how to filter data to extract just the features of interest 13 | * how to write spatial queries to find features based on whether they are within specific areas or are within proximity to one another 14 | * how to output data as CSV and JSON for use in other tools 15 | 16 | ## How to use the tutorial 17 | 18 | Step through each of the queries in turn. They're numbered to help you do 19 | that. 20 | 21 | Each query introduces a specific feature of the language, with subsequent 22 | queries showing variations of how to use that feature. Or how to combine it 23 | with other features to do more complex queries. 24 | 25 | Read the descriptions and then review the query. Comments are included 26 | to describe the important elements of the query. 27 | 28 | Click the green run button to try the query against the live database. 29 | 30 | Your browser will open up a new page, loading the query and the description 31 | into the [Overpass Turbo IDE](https://wiki.openstreetmap.org/wiki/Overpass_turbo). 32 | 33 | The query will run automatically so you can see the results. 34 | 35 | Many of the queries include commented out sections marked as `//TRYME`. 36 | These indicate sections of the query that you can customise to explore more 37 | of the functionality. Instructions are given in each example. 38 | 39 | Once you have the query open in the IDE, you can remove these comments to try 40 | out variations of the query. Be sure to hit the "Run" button in the IDE 41 | to see your new results. 42 | 43 | ## The geographic area for the tutorial 44 | 45 | Apart from the first query, the queries in the tutorial use the OpenStreetMap 46 | data describing an area in and around [Uluṟu](https://en.wikipedia.org/wiki/Uluṟu) within the [Uluṟu-Kata Tjuṯa National Park](https://en.wikipedia.org/wiki/Ulu%E1%B9%9Fu-Kata_Tju%E1%B9%AFa_National_Park) 47 | in Australia. 48 | 49 | Working with natural features makes it more likely that the queries will consistently 50 | return the expected results with the area. But the functionality can be applied 51 | to any area of the map. 52 | 53 | I also chose this setting to hopefully prompt a bit of reflection in the reader 54 | about how maps are created, who they are created for, and what data they contain. 55 | 56 | [Indigenous data sovereignty](https://www.stateofopendata.od4d.net/chapters/issues/indigenous-data.html) isn't the intended focus of this tutorial, but they are relevant issues for anyone 57 | creating or using open data. 58 | 59 | So I encourage you to reflect on what you learn as you run these queries. 60 | What tags are used? Who is doing the tagging? What features are significant and 61 | why? And how can OpenStreetMap empower local communities to build and maintain their own maps? 62 | 63 | ## Results not displaying? 64 | 65 | Overpass Turbo remembers which area of OpenStreetMap you were last looking at. 66 | 67 | So when you revisit it, you're usually looking at the same location. This can 68 | mean that sometimes after a query is loaded and run in the editor, you might be 69 | looking at the wrong map location. 70 | 71 | This can also happen if you're copying and pasting queries into the editor and 72 | running them manually. 73 | 74 | If this happens use the "Zoom to Data" option in the map view, which is 75 | shown as a magnifying glass icon. The map will then automatically recentre on 76 | the query results. 77 | -------------------------------------------------------------------------------- /tutorial/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Overpass Tutorial", 3 | "description": "A basic tutorial covering the key features of the Overpass language", 4 | "base-url": "https://osm-queries.ldodds.com/", 5 | "author": ["Leigh Dodds"] 6 | } 7 | --------------------------------------------------------------------------------