I am currently facing difficulties creating a DAX measure(or python script, or something else) to calculate the local distance between the most recent activity and the previous one, with all the data already present in a single table. Despite extensive research, all the examples I’ve found involve two tables, which doesn't apply to my situation.
The table contains the following columns: the ID of the card that performed the activity, the activity ID, the location ID, the registration date (note that an activity may start on the 10th, for example, but the relevant date is the end date, so in this case, the date would actually be the 11th), start and end date/time, latitude, and longitude.
The goal is for the user to be able to filter the data by the card ID and then by the registration date. Once filtered, the data should be organised by date and time, and the measure I intend to create should calculate the distance from the location of the previous record.
I realise this might sound a bit confusing, so let me clarify with some example data:
ID_CARD | ID_ACTIVITY | ID_LOCATION | CALDAY | STARTTIME | ENDTIME | LATITUDE | LONGITUDE |
---|---|---|---|---|---|---|---|
A | XXXX-XXXX-XXXX-XXXXX16 | X1 | 11/08/2024 | 11/08/2024 03:51 | 11/08/2024 04:02 | 41.00000 | -8.00000 |
A | XXXX-XXXX-XXXX-XXXXX1 | X2 | 11/08/2024 | 11/08/2024 04:07 | 11/08/2024 04:17 | 41.00001 | -8.00001 |
A | XXXX-XXXX-XXXX-XXXXX2 | X3 | 11/08/2024 | 11/08/2024 04:29 | 11/08/2024 04:59 | 41.00002 | -8.00002 |
A | XXXX-XXXX-XXXX-XXXXX3 | X4 | 11/08/2024 | 11/08/2024 06:19 | 11/08/2024 06:44 | 41.00003 | -8.00003 |
A | XXXX-XXXX-XXXX-XXXXX4 | X4 | 11/08/2024 | 11/08/2024 07:37 | 11/08/2024 08:10 | 41.00004 | -8.00004 |
B | XXXX-XXXX-XXXX-XXXXX5 | X6 | 11/08/2024 | 11/08/2024 07:54 | 11/08/2024 08:58 | 41.00005 | -8.00005 |
A | XXXX-XXXX-XXXX-XXXXX6 | X6 | 11/08/2024 | 11/08/2024 08:37 | 11/08/2024 08:40 | 41.00006 | -8.00006 |
A | XXXX-XXXX-XXXX-XXXXX7 | X7 | 11/08/2024 | 11/08/2024 08:40 | 11/08/2024 09:45 | 41.00007 | -8.00007 |
B | XXXX-XXXX-XXXX-XXXXX8 | X5 | 11/08/2024 | 11/08/2024 18:06 | 11/08/2024 18:32 | 41.00008 | -8.00008 |
B | XXXX-XXXX-XXXX-XXXXX9 | XX7 | 11/08/2024 | 11/08/2024 18:33 | 11/08/2024 18:56 | 41.00009 | -8.00009 |
B | XXXX-XXXX-XXXX-XXXXX10 | X7 | 11/08/2024 | 11/08/2024 18:57 | 11/08/2024 19:34 | 41.00010 | -8.00010 |
B | XXXX-XXXX-XXXX-XXXXX11 | X9 | 11/08/2024 | 11/08/2024 19:35 | 11/08/2024 19:59 | 41.00011 | -8.00011 |
B | XXXX-XXXX-XXXX-XXXXX12 | X2 | 11/08/2024 | 11/08/2024 20:01 | 11/08/2024 20:21 | 41.00012 | -8.00012 |
B | XXXX-XXXX-XXXX-XXXXX13 | X3 | 11/08/2024 | 11/08/2024 20:23 | 11/08/2024 21:37 | 41.00013 | -8.00013 |
A | XXXX-XXXX-XXXX-XXXXX14 | X8 | 11/08/2024 | 11/08/2024 20:57 | 11/08/2024 22:00 | 41.00014 | -8.00014 |
A | XXXX-XXXX-XXXX-XXXXX15 | X9 | 11/08/2024 | 11/08/2024 22:03 | 11/08/2024 22:34 | 41.00015 | -8.00015 |
Let's suppose that these are the data stored in the database. Now I will show what the user will see when filtering on the dashboard.
ID_CARD | ID_ACTIVITY | ID_LOCATION | CALDAY | STARTTIME | ENDTIME | LATITUDE | LONGITUDE | .distanceKM |
---|---|---|---|---|---|---|---|---|
A | XXXX-XXXX-XXXX-XXXXX16 | X1 | 11/08/2024 | 11/08/2024 03:51 | 11/08/2024 04:02 | 41.00000 | -8.00000 | 0.0 |
A | XXXX-XXXX-XXXX-XXXXX1 | X2 | 11/08/2024 | 11/08/2024 04:07 | 11/08/2024 04:17 | 41.00001 | -8.00001 | 0.2 |
A | XXXX-XXXX-XXXX-XXXXX2 | X3 | 11/08/2024 | 11/08/2024 04:29 | 11/08/2024 04:59 | 41.00002 | -8.00002 | 0.4 |
A | XXXX-XXXX-XXXX-XXXXX3 | X4 | 11/08/2024 | 11/08/2024 06:19 | 11/08/2024 06:44 | 41.00003 | -8.00003 | 0.7 |
A | XXXX-XXXX-XXXX-XXXXX4 | X4 | 11/08/2024 | 11/08/2024 07:37 | 11/08/2024 08:10 | 41.00004 | -8.00004 | 0.0 |
A | XXXX-XXXX-XXXX-XXXXX6 | X6 | 11/08/2024 | 11/08/2024 08:37 | 11/08/2024 08:40 | 41.00006 | -8.00006 | 1.0 |
A | XXXX-XXXX-XXXX-XXXXX7 | X7 | 11/08/2024 | 11/08/2024 08:40 | 11/08/2024 09:45 | 41.00007 | -8.00007 | 0.9 |
A | XXXX-XXXX-XXXX-XXXXX14 | X8 | 11/08/2024 | 11/08/2024 20:57 | 11/08/2024 22:00 | 41.00014 | -8.00014 | 0.2 |
A | XXXX-XXXX-XXXX-XXXXX15 | X9 | 11/08/2024 | 11/08/2024 22:03 | 11/08/2024 22:34 | 41.00015 | -8.00015 | 0.5 |
This is what the user will see when applying the filters; the .distanceKM will be calculated in the order of the records. I hope this is enough for you to understand my question. I look forward to the resolution of this issue or even a suggestion.
P.S.: I had to create random data to protect confidential information, but I think the idea is clear.
Try a Measure similar to:
.distanceKM =
var thisLat = MAX('YourTable'[LATITUDE])
var thisLng = MAX('YourTable'[LONGITUDE])
var prevRow = OFFSET(-1, DISTINCT(ALLSELECTED('YourTable')), ORDERBY([ENDTIME], ASC))
var prevLat = CALCULATE(MAX('YourTable'[LATITUDE]), prevRow)
var prevLng = CALCULATE(MAX('YourTable'[LONGITUDE]), prevRow)
// from 2nd answer at https://stackoverflow.com/a/21623206/21688343
var r = 6371 // Earth's radius in KM
var p = DIVIDE( PI(), 180 )
var a = 0.5 - DIVIDE(COS( (thisLat - prevLat) * p), 2) + COS(prevLat * p) * COS(thisLat * p) * DIVIDE(1 - COS((thisLng - prevLng) * p), 2)
var dist = 2 * r * ASIN(SQRT(a))
return IF(NOT ISBLANK(prevLat), dist, 0)
The main part is using OFFSET
to get the previous row.
See https://pbidax.wordpress.com/2022/12/23/introducing-dax-window-functions-part-2/ for a good write-up on it.