Skip to content

Commit

Permalink
feat(geo): add geo.totalDistance to aggregate total distance (#5358)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderson committed Jan 6, 2023
1 parent 8c5176f commit e28ecc7
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 1 deletion.
3 changes: 2 additions & 1 deletion libflux/go/libflux/buildinfo.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ var sourceHashes = map[string]string{
"stdlib/experimental/geo/filterRowsNotStrict_test.flux": "890919ac33bde919f4d1141932c44d4fd9401c3f30cd24f19e2aa0ef09e418cc",
"stdlib/experimental/geo/filterRowsPivoted_test.flux": "25d56c93b61818606810c0ec7279a03deec9712a44a81eeb86957067d7bb2ee0",
"stdlib/experimental/geo/filterRowsStrict_test.flux": "397c4ff9001976d268876574160c256563a1d5983101d54f4ec7fb9b91c45c5f",
"stdlib/experimental/geo/geo.flux": "c1082cb5b299e270065af5d8f4711a25a0410a4855316736ad5f2af59f07ce6b",
"stdlib/experimental/geo/geo.flux": "31dac744eca608ade85772ebbdc26f46d7f9c742051ac3be4f94efb309f6e950",
"stdlib/experimental/geo/gridFilterLevel_test.flux": "f9d7c9b79a91cfcff7b4cd29a3b511fc397cb8666481a1ac40f0d8f28d94e146",
"stdlib/experimental/geo/gridFilter_test.flux": "6de30bc0d5672a18d4d4e0351efabb9d24b783b71945faa6f67302ac4409b225",
"stdlib/experimental/geo/groupByArea_test.flux": "cce3a07b36b7b30a51b1f55ff495cc86ef4f673d95928e8b18641ba3a8b2db30",
Expand All @@ -185,6 +185,7 @@ var sourceHashes = map[string]string{
"stdlib/experimental/geo/st_intersects_linestring_test.flux": "899f3ea45982580be75d6a18f9caf24e44e08d5a2b6e423dcf5e9467ed1a015f",
"stdlib/experimental/geo/st_length_linestring_test.flux": "9525cf4d69c279ae1e34ae54ca3e2688eee22fd16493e99290cea5b1d8a503f9",
"stdlib/experimental/geo/strictFilter_test.flux": "52894ad4469540c185e87599f1bd0cdb966d74fe6f1ae0d299a9dee665f51689",
"stdlib/experimental/geo/totalDistance_test.flux": "b3aa9a627a3de714140a6c363128cbcce8d85d4094f27a554b5baeb5e4b55e2f",
"stdlib/experimental/geo/units_miles_test.flux": "b1029be1f5c7aecf282a5aa6e164576939cced7d4d06ec211d990aa9a865a041",
"stdlib/experimental/group_test.flux": "eabe72efa7bd5f2eb30a6e6afb19b65157d167b15740afa85d0f0849cd2fab94",
"stdlib/experimental/histogram_quantile_test.flux": "7c4ad5de961f1c770d691747d07fce87ef972deec684f8795b899f1dd6140f05",
Expand Down
95 changes: 95 additions & 0 deletions stdlib/experimental/geo/geo.flux
Original file line number Diff line number Diff line change
Expand Up @@ -1009,3 +1009,98 @@ asTracks = (tables=<-, groupBy=["id", "tid"], orderBy=["_time"]) =>
tables
|> group(columns: groupBy)
|> sort(columns: orderBy)

// totalDistance calculates the total distance covered by subsequent points
// in each input table.
//
// Each row must contain `lat` (latitude) and `lon` (longitude) columns that
// represent the geographic coordinates of the point.
// Row sort order determines the order in which distance between points is calculated.
// Use the `geo.units` option to specify the unit of distance to return (default is km).
//
// ## Parameters
// - outputColumn: Total distance output column. Default is `_value`.
// - tables: Input data. Default is piped-forward data (`<-`).
//
// ## Examples
//
// ### Return the total distance travelled per input table
// ```
// # import "array"
// import "experimental/geo"
//
// # data =
// # array.from(
// # rows: [
// # {id: "ABC1", _time: 2022-01-01T00:00:00Z, lat: 85.1, lon: 42.2},
// # {id: "ABC1", _time: 2022-01-01T01:00:00Z, lat: 71.3, lon: 50.8},
// # {id: "ABC1", _time: 2022-01-01T02:00:00Z, lat: 63.1, lon: 62.3},
// # {id: "ABC1", _time: 2022-01-01T03:00:00Z, lat: 50.6, lon: 74.9},
// # {id: "DEF2", _time: 2022-01-01T00:00:00Z, lat: -10.8, lon: -12.2},
// # {id: "DEF2", _time: 2022-01-01T01:00:00Z, lat: -16.3, lon: -0.8},
// # {id: "DEF2", _time: 2022-01-01T02:00:00Z, lat: -23.2, lon: 12.3},
// # {id: "DEF2", _time: 2022-01-01T03:00:00Z, lat: -30.4, lon: 24.9},
// # ],
// # )
// # |> group(columns: ["id"])
// #
// < data
// > |> geo.totalDistance()
// ```
//
// ### Return the total distance travelled in miles
// ```
// # import "array"
// import "experimental/geo"
//
// option geo.units = {distance: "mile"}
//
// # data =
// # array.from(
// # rows: [
// # {id: "ABC1", _time: 2022-01-01T00:00:00Z, lat: 85.1, lon: 42.2},
// # {id: "ABC1", _time: 2022-01-01T01:00:00Z, lat: 71.3, lon: 50.8},
// # {id: "ABC1", _time: 2022-01-01T02:00:00Z, lat: 63.1, lon: 62.3},
// # {id: "ABC1", _time: 2022-01-01T03:00:00Z, lat: 50.6, lon: 74.9},
// # {id: "DEF2", _time: 2022-01-01T00:00:00Z, lat: -10.8, lon: -12.2},
// # {id: "DEF2", _time: 2022-01-01T01:00:00Z, lat: -16.3, lon: -0.8},
// # {id: "DEF2", _time: 2022-01-01T02:00:00Z, lat: -23.2, lon: 12.3},
// # {id: "DEF2", _time: 2022-01-01T03:00:00Z, lat: -30.4, lon: 24.9},
// # ],
// # )
// # |> group(columns: ["id"])
// #
// < data
// > |> geo.totalDistance()
// ```
//
// ## Metadata
// introduced: NEXT
// tags: transformations, geotemporal, aggregates
//
totalDistance = (tables=<-, outputColumn="_value") =>
tables
|> reduce(
identity: {index: 0, lat: 0.0, lon: 0.0, totalDistance: 0.0},
fn: (r, accumulator) => {
_lastPoint =
if accumulator.index == 0 then
{lat: r.lat, lon: r.lon}
else
{lat: accumulator.lat, lon: accumulator.lon}
_currentPoint = {lat: r.lat, lon: r.lon}

return {
index: accumulator.index + 1,
lat: r.lat,
lon: r.lon,
totalDistance:
accumulator.totalDistance + ST_Distance(
region: _lastPoint,
geometry: _currentPoint,
),
}
},
)
|> drop(columns: ["index", "lat", "lon"])
|> rename(columns: {totalDistance: outputColumn})
61 changes: 61 additions & 0 deletions stdlib/experimental/geo/totalDistance_test.flux
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package geo_test


import "array"
import "experimental/geo"
import "testing"

testcase geo_total_distance_testcase {
got =
array.from(
rows: [
{id: "ABC1", _time: 2022-01-01T00:00:00Z, lat: 85.1, lon: 42.2},
{id: "ABC1", _time: 2022-01-01T01:00:00Z, lat: 71.3, lon: 50.8},
{id: "ABC1", _time: 2022-01-01T02:00:00Z, lat: 63.1, lon: 62.3},
{id: "ABC1", _time: 2022-01-01T03:00:00Z, lat: 50.6, lon: 74.9},
{id: "DEF2", _time: 2022-01-01T00:00:00Z, lat: -10.8, lon: -12.2},
{id: "DEF2", _time: 2022-01-01T01:00:00Z, lat: -16.3, lon: -0.8},
{id: "DEF2", _time: 2022-01-01T02:00:00Z, lat: -23.2, lon: 12.3},
{id: "DEF2", _time: 2022-01-01T03:00:00Z, lat: -30.4, lon: 24.9},
],
)
|> group(columns: ["id"])
|> geo.totalDistance()

want =
array.from(
rows: [
{id: "ABC1", _value: 4157.144498077607},
{id: "DEF2", _value: 4428.129653320098},
],
)
|> group(columns: ["id"])

testing.diff(got: got, want: want)
}

testcase geo_total_distance_custom_column_testcase {
got =
array.from(
rows: [
{id: "ABC1", _time: 2022-01-01T00:00:00Z, lat: 85.1, lon: 42.2},
{id: "ABC1", _time: 2022-01-01T01:00:00Z, lat: 71.3, lon: 50.8},
{id: "ABC1", _time: 2022-01-01T02:00:00Z, lat: 63.1, lon: 62.3},
{id: "ABC1", _time: 2022-01-01T03:00:00Z, lat: 50.6, lon: 74.9},
{id: "DEF2", _time: 2022-01-01T00:00:00Z, lat: -10.8, lon: -12.2},
{id: "DEF2", _time: 2022-01-01T01:00:00Z, lat: -16.3, lon: -0.8},
{id: "DEF2", _time: 2022-01-01T02:00:00Z, lat: -23.2, lon: 12.3},
{id: "DEF2", _time: 2022-01-01T03:00:00Z, lat: -30.4, lon: 24.9},
],
)
|> group(columns: ["id"])
|> geo.totalDistance(outputColumn: "foo")

want =
array.from(
rows: [{id: "ABC1", foo: 4157.144498077607}, {id: "DEF2", foo: 4428.129653320098}],
)
|> group(columns: ["id"])

testing.diff(got: got, want: want)
}

0 comments on commit e28ecc7

Please sign in to comment.