Forum Discussion
Joaomatos2002
2 years agoFrequent Visitor
Assistance Needed with DAX Measure for Calculating Sequential Distance in Power BI
Hi, I hope this message finds you well. I am currently facing difficulties creating a DAX measure to calculate the local distance between the most recent activity and the previous one, with a...
- 2 years ago
Hi Joaomatos2002,
Comment: are you sure that you have correct distance calculated in your sample?
DAX solution (power bi files attached. First as a simple measure, second with calculated columns as helper)
Output
Create as a new measure:
Distance KM = VAR _IDCard = SELECTEDVALUE(Table1[ID_CARD]) VAR _endTime = SELECTEDVALUE(Table1[ENDTIME]) VAR _lat = SELECTEDVALUE(Table1[latitude]) VAR _lon = SELECTEDVALUE(Table1[longitude]) VAR _PI_D180 = PI()/180 VAR _tbl = TOPN( 1, FILTER( ALL(Table1), Table1[ID_CARD] = _IDCard && Table1[ENDTIME] < _endTime ), [ENDTIME], DESC ) VAR _latPrev = COALESCE( CALCULATE( MIN(Table1[latitude]), _tbl ), _lat ) VAR _lonPrev = COALESCE( CALCULATE( MIN(Table1[longitude]), _tbl ), _lon ) VAR _result = ACOS(SIN(_lat*_PI_D180)*SIN(_latPrev*_PI_D180)+COS(_lat*_PI_D180)*COS(_latPrev*_PI_D180)*COS((_lonPrev*_PI_D180)-(_lon*_PI_D180)))*6371 VAR _result2 = IF(ISINSCOPE(Table1[ID_CARD]), _result) RETURN _result2Power Query solution:
Output:
let fnShift = (tbl as table, col as text, shift as nullable number, optional newColName as text, optional _type as type) as table => //v 3. parametri zadaj zaporne cislo ak chces posunut riadky hore, kladne ak dole, 4. je nepovinny (novy nazov stlpca), 5. je nepovinny typ let a = Table.Column(tbl, col), b = if shift = 0 or shift = null then a else if shift > 0 then List.Repeat({null}, shift) & List.RemoveLastN(a, shift) else List.RemoveFirstN(a, shift * -1) & List.Repeat({null}, shift * -1), c = Table.FromColumns(Table.ToColumns(tbl) & {b}, Table.ColumnNames(tbl) & ( if newColName <> null then {newColName} else if shift = 0 then {col & "_Duplicate"} else if shift > 0 then {col & "_PrevValue"} else {col & "_NextValue"} )), d = Table.TransformColumnTypes(c, {List.Last(Table.ColumnNames(c)), if _type <> null then _type else type any}) in d, fnDistance = (lat1 as number, lon1 as number, lat2 as number, lon2 as number, optional km_or_mi as text)=> let lat1_rad = lat1/ 180 * Number.PI, lon1_rad = lon1 / 180 * Number.PI, lat2_rad = lat2/ 180 * Number.PI, lon2_rad = lon2 / 180 * Number.PI, unit = if km_or_mi = "mi" then 3959 else 6371, //Earth radius 3959 for miles, 6371 for kilometers distance = Number.Acos(Number.Sin(lat1_rad) * Number.Sin(lat2_rad) + Number.Cos(lat1_rad) * Number.Cos(lat2_rad) * Number.Cos(lon2_rad-lon1_rad)) * unit in distance, fnCalc = (myTable as table)=> [ // _Detail = GroupedRows{[ID_CARD="A"]}[fnCalc], _Detail = myTable, _SortedRows = Table.Sort(_Detail, {{"ENDTIME", Order.Ascending}}), _Ad_LatLong_PrevValues = fnShift(fnShift(_SortedRows, "latitude", 1, null, type number), "longitude", 1, null, type number), _Ad_Distance = Table.AddColumn(_Ad_LatLong_PrevValues, "distanceKM", each fnDistance([latitude], [longitude], [latitude_PrevValue]? ?? [latitude], [longitude_PrevValue]? ?? [longitude], "km"), type number), _RemovedColumns = Table.RemoveColumns(_Ad_Distance, {"latitude_PrevValue", "longitude_PrevValue"}) ][_RemovedColumns], Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("hdRLjsMgEATQq4y8TiZU82c3cwpLke9/jQEmUtmQNF5YuCz1E79+Pref7bbt9blfXztC+4H6Ah4mPcSIu3x8GVs8hsgVIzVy+DbtqcN7eg2Pm4K1XDSrFo5ThEgLtKBajdmtbkmeIp9pCS1RrcbsTrNCwWiF4hwtS8uqlltasdhxDVOBoeVouW79frB8y4Nu+TFKxSdanpZX5xWWVno3L3eaV6AVVKuV2aNu9cLnKBfnaUVaUV3DthZ9IT9ZSMWEKbKn+5VoJdXKPdcm1irbKfKBWCaWVayfqBXmhx1DLpanHuwcMDrWW0fWsFrZT9HpOoOtA9AxWfUpMcVgigTE2DsgOmZXjapVHvZM8H8XXhibB/Tmgd49ko6NeyZSDG8Z2D3gdMyv9qxVHmcmlwPC9lGHx/EH", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID_CARD = _t, ID_ACTIVITY = _t, ID_LOCATION = _t, CALDAY = _t, STARTTIME = _t, ENDTIME = _t, latitude = _t, longitude = _t]), ChangedType = Table.TransformColumnTypes(Source,{{"ID_CARD", type text}, {"ID_ACTIVITY", type text}, {"ID_LOCATION", type text}, {"CALDAY", type date}, {"STARTTIME", type datetime}, {"ENDTIME", type datetime}}), ChangedTypeUS = Table.TransformColumnTypes(ChangedType,{{"latitude", type number}, {"longitude", type number}}, "en-US"), GroupedRows = Table.Group(ChangedTypeUS, {"ID_CARD"}, {{"fnCalc", fnCalc, type table}}), Combined = Table.Combine(GroupedRows[fnCalc]) in Combined
dufoq3
Community Champion
2 years agoHi Joaomatos2002,
Comment: are you sure that you have correct distance calculated in your sample?
DAX solution (power bi files attached. First as a simple measure, second with calculated columns as helper)
Output
Create as a new measure:
Distance KM =
VAR _IDCard = SELECTEDVALUE(Table1[ID_CARD])
VAR _endTime = SELECTEDVALUE(Table1[ENDTIME])
VAR _lat = SELECTEDVALUE(Table1[latitude])
VAR _lon = SELECTEDVALUE(Table1[longitude])
VAR _PI_D180 = PI()/180
VAR _tbl =
TOPN(
1,
FILTER(
ALL(Table1),
Table1[ID_CARD] = _IDCard &&
Table1[ENDTIME] < _endTime
),
[ENDTIME],
DESC
)
VAR _latPrev =
COALESCE(
CALCULATE(
MIN(Table1[latitude]),
_tbl
),
_lat
)
VAR _lonPrev =
COALESCE(
CALCULATE(
MIN(Table1[longitude]),
_tbl
),
_lon
)
VAR _result = ACOS(SIN(_lat*_PI_D180)*SIN(_latPrev*_PI_D180)+COS(_lat*_PI_D180)*COS(_latPrev*_PI_D180)*COS((_lonPrev*_PI_D180)-(_lon*_PI_D180)))*6371
VAR _result2 = IF(ISINSCOPE(Table1[ID_CARD]), _result)
RETURN _result2
Power Query solution:
Output:
let
fnShift = (tbl as table, col as text, shift as nullable number, optional newColName as text, optional _type as type) as table =>
//v 3. parametri zadaj zaporne cislo ak chces posunut riadky hore, kladne ak dole, 4. je nepovinny (novy nazov stlpca), 5. je nepovinny typ
let
a = Table.Column(tbl, col),
b = if shift = 0 or shift = null then a else if shift > 0
then List.Repeat({null}, shift) & List.RemoveLastN(a, shift)
else List.RemoveFirstN(a, shift * -1) & List.Repeat({null}, shift * -1),
c = Table.FromColumns(Table.ToColumns(tbl) & {b}, Table.ColumnNames(tbl) &
( if newColName <> null then {newColName} else
if shift = 0 then {col & "_Duplicate"} else
if shift > 0 then {col & "_PrevValue"}
else {col & "_NextValue"} )),
d = Table.TransformColumnTypes(c, {List.Last(Table.ColumnNames(c)), if _type <> null then _type else type any})
in
d,
fnDistance =
(lat1 as number, lon1 as number, lat2 as number, lon2 as number, optional km_or_mi as text)=>
let
lat1_rad = lat1/ 180 * Number.PI,
lon1_rad = lon1 / 180 * Number.PI,
lat2_rad = lat2/ 180 * Number.PI,
lon2_rad = lon2 / 180 * Number.PI,
unit = if km_or_mi = "mi" then 3959 else 6371, //Earth radius 3959 for miles, 6371 for kilometers
distance = Number.Acos(Number.Sin(lat1_rad) * Number.Sin(lat2_rad) + Number.Cos(lat1_rad) * Number.Cos(lat2_rad) * Number.Cos(lon2_rad-lon1_rad)) * unit
in
distance,
fnCalc =
(myTable as table)=>
[
// _Detail = GroupedRows{[ID_CARD="A"]}[fnCalc],
_Detail = myTable,
_SortedRows = Table.Sort(_Detail, {{"ENDTIME", Order.Ascending}}),
_Ad_LatLong_PrevValues = fnShift(fnShift(_SortedRows, "latitude", 1, null, type number), "longitude", 1, null, type number),
_Ad_Distance = Table.AddColumn(_Ad_LatLong_PrevValues, "distanceKM", each fnDistance([latitude], [longitude], [latitude_PrevValue]? ?? [latitude], [longitude_PrevValue]? ?? [longitude], "km"), type number),
_RemovedColumns = Table.RemoveColumns(_Ad_Distance, {"latitude_PrevValue", "longitude_PrevValue"})
][_RemovedColumns],
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("hdRLjsMgEATQq4y8TiZU82c3cwpLke9/jQEmUtmQNF5YuCz1E79+Pref7bbt9blfXztC+4H6Ah4mPcSIu3x8GVs8hsgVIzVy+DbtqcN7eg2Pm4K1XDSrFo5ThEgLtKBajdmtbkmeIp9pCS1RrcbsTrNCwWiF4hwtS8uqlltasdhxDVOBoeVouW79frB8y4Nu+TFKxSdanpZX5xWWVno3L3eaV6AVVKuV2aNu9cLnKBfnaUVaUV3DthZ9IT9ZSMWEKbKn+5VoJdXKPdcm1irbKfKBWCaWVayfqBXmhx1DLpanHuwcMDrWW0fWsFrZT9HpOoOtA9AxWfUpMcVgigTE2DsgOmZXjapVHvZM8H8XXhibB/Tmgd49ko6NeyZSDG8Z2D3gdMyv9qxVHmcmlwPC9lGHx/EH", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID_CARD = _t, ID_ACTIVITY = _t, ID_LOCATION = _t, CALDAY = _t, STARTTIME = _t, ENDTIME = _t, latitude = _t, longitude = _t]),
ChangedType = Table.TransformColumnTypes(Source,{{"ID_CARD", type text}, {"ID_ACTIVITY", type text}, {"ID_LOCATION", type text}, {"CALDAY", type date}, {"STARTTIME", type datetime}, {"ENDTIME", type datetime}}),
ChangedTypeUS = Table.TransformColumnTypes(ChangedType,{{"latitude", type number}, {"longitude", type number}}, "en-US"),
GroupedRows = Table.Group(ChangedTypeUS, {"ID_CARD"}, {{"fnCalc", fnCalc, type table}}),
Combined = Table.Combine(GroupedRows[fnCalc])
in
Combined