Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Applies to: ✅ Azure Data Explorer
The geo_polygon_lookup plugin looks up a Polygon value in a lookup table and returns rows with matched values. The plugin is invoked with the evaluate operator.
Syntax
T | evaluate geo_polygon_lookup( LookupTable , LookupPolygonKey , SourceLongitude , SourceLatitude , [ radius ] , [ return_unmatched ] , [ lookup_area_radius ] , [ return_lookup_key ] )
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| T | string |
✔️ | The tabular input whose columns SourceLongitude and SourceLatitude are used for polygon matching. |
| LookupTable | string |
✔️ | Table or tabular expression with polygons lookup data, whose column LookupPolygonKey is used for polygon matching. |
| LookupPolygonKey | dynamic |
✔️ | The column of LookupTable with Polygon or multipolygon in the GeoJSON format and of dynamic type that is matched against each SourceLongitude, SourceLatitudes values. |
| SourceLongitude | real |
✔️ | The column of T with longitude value to be looked up in LookupTable. Longitude value in degrees. Valid value is a real number and in the range [-180, +180]. |
| SourceLatitude | real |
✔️ | The column of T with latitude value to be looked up in LookupTable. Latitude value in degrees. Valid value is a real number and in the range [-90, +90]. |
| radius | real |
An optional radius value that defines the length from the polygon borders where the location is considered a match. | |
| return_unmatched | bool |
An optional boolean flag that defines if the result should include all or only matching rows (default: false - only matching rows returned). |
|
| lookup_area_radius | real |
An optional lookup area radius distance in meters value that might help in matching locations to their respective polygons. | |
| return_lookup_key | bool |
An optional boolean flag that defines if the result should include column LookupPolygonKey (default: false). |
Returns
The geo_polygon_lookup plugin returns a result of join (lookup). The schema of the table is the union of the source table and the lookup table, similar to the result of the lookup operator.
Point containment in polygon is tested via geo_point_in_polygon(), or if radius is set, then geo_distance_point_to_polygon().
If the return_unmatched argument is set to true, the resulting table includes both matched and unmatched rows (filled with nulls).
If the return_unmatched argument is set to false, or omitted (the default value of false is used), the resulting table has as many records as matching results. This variant of lookup has better performance compared to return_unmatched=true execution.
Setting lookup_area_radius length overrides internal matching mechanism and might improve or worsen run time and\or memory consumption. It doesn't affect query correctness. Read more below on how to set this optional value.
Note
- This plugin covers the scenario of classifying locations to polygons, assuming a small lookup table size, with the input table optionally having a larger size.
- The performance of the plugin depends on the sizes of the lookup and data source tables, the number of columns, and number of matching records.
- The geospatial coordinates are interpreted as represented by the WGS-84 coordinate reference system.
- The geodetic datum used for measurements on Earth is a sphere. Polygon edges are geodesics on the sphere.
- If input polygon edges are straight cartesian lines, consider using geo_polygon_densify() to convert planar edges to geodesics.
- Input polygons should be valid.
Polygon definition and constraints
dynamic({"type": "Polygon","coordinates": [ LinearRingShell, LinearRingHole_1, ..., LinearRingHole_N ]})
dynamic({"type": "MultiPolygon","coordinates": [[LinearRingShell, LinearRingHole_1, ..., LinearRingHole_N ], ..., [LinearRingShell, LinearRingHole_1, ..., LinearRingHole_M]]})
- LinearRingShell is required and defined as a
counterclockwiseordered array of coordinates [[lng_1,lat_1],...,[lng_i,lat_i],...,[lng_j,lat_j],...,[lng_1,lat_1]]. There can be only one shell. - LinearRingHole is optional and defined as a
clockwiseordered array of coordinates [[lng_1,lat_1],...,[lng_i,lat_i],...,[lng_j,lat_j],...,[lng_1,lat_1]]. There can be any number of interior rings and holes. - LinearRing vertices must be distinct with at least three coordinates. The first coordinate must be equal to the last. At least four entries are required.
- Coordinates [longitude, latitude] must be valid. Longitude must be a real number in the range [-180, +180] and latitude must be a real number in the range [-90, +90].
- LinearRingShell encloses at most half of the sphere. LinearRing divides the sphere into two regions. The smaller of the two regions, is chosen.
- LinearRing edge length must be less than 180 degrees. The shortest edge between the two vertices is chosen.
- LinearRings must not cross and must not share edges. LinearRings might share vertices.
Note
- Polygon doesn't necessarily contain its vertices. Point containment in polygon is defined so that if the Earth is subdivided into polygons, every point is contained by exactly one polygon. Hence, setting Radius = 0 isn't equal to not setting it.
Setting lookup_area_radius (if needed)
Setting lookup area radius overrides internal mechanism for matching locations to their respective polygons. The value is a distance in meters. Ideally, lookup area radius should represent a distance from polygon center, such that within that distance a point matches to exactly one polygon in one-to-one manner and within that distance, there are no more than a single polygon. Because the polygons data might be large, polygons might vary greatly in size and shape compared to each other and the proximity of the polygon one to another, it might be challenging to come up with the radius that performs the best. If needed, here's a sample that might help.
PolygonsTable | project value = sqrt(geo_polygon_area(polygon)) | summarize min = min(value), avg = avg(value), max = max(value)
Try using lookup radius starting from average value towards either minimum (If the polygons are close to each other) or maximum by multiples of 2.
Tip
- If the Locations table has too many coordinates that are close to each other, consider aggregating them using geo_point_to_s2cell().
- If you want to know if any of the polygons contains a point, try the following steps: Fold the collection of polygons into one multipolygon. Then query this multipolygon. This method might improve performance. See the following example.
- It might be possible to build a more personalized (or performant) join functionality using geo_polygon_to_s2cells().
Examples
The following example returns only matching rows.
let polygons = datatable(polygon_name:string, polygon:dynamic)
[
"New York", dynamic({"type":"Polygon", "coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331991,40.74112695466084],[-73.97375470114766,40.74300078124614]]]}),
"Paris", dynamic({"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921334],[2.420098611499384,49.05163394896812],[2.1016783119165723,48.80113794475062],[2.57564669886321,48.769567764921334]]]}),
];
let locations = datatable(location_name:string, longitude:real, latitude:real)
[
"Empire State Building", -73.98567337898565, 40.74842629977377,
"National Museum of Mathematics", -73.98778501496217, 40.743565232771545,
"Eiffel Tower", 2.294489426068907, 48.858263476169185,
"London", -0.13245599272019604, 51.49879464208368,
"Statue of Liberty", -74.04462223203123, 40.689195627512674,
];
locations
| evaluate geo_polygon_lookup(polygons, polygon, longitude, latitude, return_lookup_key = true)
Output
| location_name | longitude | latitude | polygon_name | polygon |
|---|---|---|---|---|
| NY National Museum of Mathematics | -73.9877850149622 | 40.7435652327715 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Empire State Building | -73.9856733789857 | 40.7484262997738 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Eiffel Tower | 2.29448942606891 | 48.8582634761692 | Paris | {"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921337],[2.420098611499384,49.05163394896812],[2.1016783119165725,48.80113794475062],[2.57564669886321,48.769567764921337]]]} |
The following example returns both matching and nonmatching rows.
let polygons = datatable(polygon_name:string, polygon:dynamic)
[
"New York", dynamic({"type":"Polygon", "coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331991,40.74112695466084],[-73.97375470114766,40.74300078124614]]]}),
"Paris", dynamic({"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921334],[2.420098611499384,49.05163394896812],[2.1016783119165723,48.80113794475062],[2.57564669886321,48.769567764921334]]]}),
];
let locations = datatable(location_name:string, longitude:real, latitude:real)
[
"Empire State Building", -73.98567337898565, 40.74842629977377,
"NY National Museum of Mathematics", -73.98778501496217, 40.743565232771545,
"Eiffel Tower", 2.294489426068907, 48.858263476169185,
"London", -0.13245599272019604, 51.49879464208368,
"Statue of Liberty", -74.04462223203123, 40.689195627512674,
];
locations
| evaluate geo_polygon_lookup(polygons, polygon, longitude, latitude, return_unmatched = true, return_lookup_key = true)
Output
| location_name | longitude | latitude | polygon_name | polygon |
|---|---|---|---|---|
| NY National Museum of Mathematics | -73.9877850149622 | 40.7435652327715 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Empire State Building | -73.9856733789857 | 40.7484262997738 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Eiffel Tower | 2.29448942606891 | 48.8582634761692 | Paris | {"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921337],[2.420098611499384,49.05163394896812],[2.1016783119165725,48.80113794475062],[2.57564669886321,48.769567764921337]]]} |
| Statue of Liberty | -74.04462223203123 | 40.689195627512674 | ||
| London | -0.13245599272019604 | 51.498794642083681 |
The following example returns both matching and nonmatching rows where radius is set to 7 km.
let polygons = datatable(polygon_name:string, polygon:dynamic)
[
"New York", dynamic({"type":"Polygon", "coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331991,40.74112695466084],[-73.97375470114766,40.74300078124614]]]}),
"Paris", dynamic({"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921334],[2.420098611499384,49.05163394896812],[2.1016783119165723,48.80113794475062],[2.57564669886321,48.769567764921334]]]}),
];
let locations = datatable(location_name:string, longitude:real, latitude:real)
[
"Empire State Building", -73.98567337898565, 40.74842629977377,
"NY National Museum of Mathematics", -73.98778501496217, 40.743565232771545,
"Eiffel Tower", 2.294489426068907, 48.858263476169185,
"London", -0.13245599272019604, 51.49879464208368,
"Statue of Liberty", -74.04462223203123, 40.689195627512674,
];
locations
| evaluate geo_polygon_lookup(polygons, polygon, longitude, latitude, radius = 7000, return_unmatched = true, return_lookup_key = true)
Output
| location_name | longitude | latitude | polygon_name | polygon |
|---|---|---|---|---|
| NY National Museum of Mathematics | -73.9877850149622 | 40.7435652327715 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Empire State Building | -73.9856733789857 | 40.7484262997738 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| Eiffel Tower | 2.29448942606891 | 48.8582634761692 | Paris | {"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921337],[2.420098611499384,49.05163394896812],[2.1016783119165725,48.80113794475062],[2.57564669886321,48.769567764921337]]]} |
| Statue of Liberty | -74.04462223203123 | 40.689195627512674 | New York | {"type":"Polygon","coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331992,40.74112695466084],[-73.97375470114766,40.74300078124614]]]} |
| London | -0.13245599272019604 | 51.498794642083681 |
The following example counts locations by polygon.
let polygons = datatable(polygon_name:string, polygon:dynamic)
[
"New York", dynamic({"type":"Polygon", "coordinates":[[[-73.97375470114766,40.74300078124614],[-73.98653921014294,40.75486501361894],[-73.99910622331991,40.74112695466084],[-73.97375470114766,40.74300078124614]]]}),
"Paris", dynamic({"type":"Polygon","coordinates":[[[2.57564669886321,48.769567764921334],[2.420098611499384,49.05163394896812],[2.1016783119165723,48.80113794475062],[2.57564669886321,48.769567764921334]]]}),
];
let locations = datatable(location_name:string, longitude:real, latitude:real)
[
"Empire State Building", -73.98567337898565, 40.74842629977377,
"NY National Museum of Mathematics", -73.98778501496217, 40.743565232771545,
"Eiffel Tower", 2.294489426068907, 48.858263476169185,
"London", -0.13245599272019604, 51.49879464208368,
"Statue of Liberty", -74.04462223203123, 40.689195627512674,
];
locations
| evaluate geo_polygon_lookup(polygons, polygon, longitude, latitude)
| summarize count() by polygon_name
Output
| polygon_name | count_ |
|---|---|
| New York | 2 |
| Paris | 1 |
Related content
- Overview of geo_point_in_polygon()
- Overview of geo_distance_point_to_polygon()
- Overview of geo_polygon_to_s2cells()