From 71b0c76fe9594e06fde9c010f1329eac664279e3 Mon Sep 17 00:00:00 2001 From: Yun-Wu Date: Mon, 21 Oct 2024 22:47:27 +0800 Subject: [PATCH] Add NSD Calculation (#302) --- ecoscope/base/base.py | 8 ++++++ tests/test_base.py | 24 ++++++++++++++++++ .../geofence_crossing_point.feather | Bin 15578 -> 17418 bytes 3 files changed, 32 insertions(+) diff --git a/ecoscope/base/base.py b/ecoscope/base/base.py index 38234a45..776109b2 100644 --- a/ecoscope/base/base.py +++ b/ecoscope/base/base.py @@ -412,6 +412,7 @@ def _create_trajsegments(gdf): "heading": track_properties.heading, "geometry": shapely.linestrings(coords), "junk_status": gdf.junk_status, + "nsd": track_properties.nsd, }, crs=4326, index=gdf.index, @@ -625,6 +626,13 @@ def dist_meters(self): _, _, distance = self.inverse_transformation return distance + @property + def nsd(self): + start_point = df["geometry"].iloc[0] + geod = Geod(ellps="WGS84") + geod_displacement = [geod.inv(start_point.x, start_point.y, geo.x, geo.y)[2] for geo in df["_geometry"]] + return [(x**2) / (1000 * 2) for x in geod_displacement] + @property def timespan_seconds(self): return (df["_fixtime"] - df["fixtime"]).dt.total_seconds() diff --git a/tests/test_base.py b/tests/test_base.py index a2c21677..18c10e26 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -50,6 +50,30 @@ def test_relocations_from_gdf_preserve_fields(er_io): gpd.testing.assert_geodataframe_equal(relocations, ecoscope.base.Relocations.from_gdf(relocations)) +def test_trajectory_properties(movebank_relocations): + trajectory = ecoscope.base.Trajectory.from_relocations(movebank_relocations) + + assert "groupby_col" in trajectory + assert "segment_start" in trajectory + assert "segment_end" in trajectory + assert "timespan_seconds" in trajectory + assert "speed_kmhr" in trajectory + assert "heading" in trajectory + assert "geometry" in trajectory + assert "junk_status" in trajectory + assert "nsd" in trajectory + + trajectory = trajectory.loc[trajectory.groupby_col == "Habiba"].head(5) + + expected_nsd = pd.Series( + [0.446425, 1.803153, 2.916319, 28.909629, 72.475410], + dtype=np.float64, + index=pd.Index([368706890, 368706891, 368706892, 368706893, 368706894], name="event-id"), + name="nsd", + ) + pandas.testing.assert_series_equal(trajectory["nsd"], expected_nsd) + + def test_displacement_property(movebank_relocations): trajectory = ecoscope.base.Trajectory.from_relocations(movebank_relocations) expected = pd.Series( diff --git a/tests/test_output/geofence_crossing_point.feather b/tests/test_output/geofence_crossing_point.feather index f0ed3ad3b75b61747db52b73a9ac48ffd704bb8d..cd4bf130e617e04b7546bc36a1a585949046003e 100644 GIT binary patch literal 17418 zcmeGkZEPIHbuMvY6C7&tK^;EY%Ow(a8(;2YeIIE`_DF*xnt*Eu5-G7Rdv|O5?7Q7# zZ!fXqy16D*iD*%2)e4G0K#NLMP@AB%gqDJ(QVCMps7RsEs*rw3p{R{P4MKdm@6FDv zcW2L098AlP8}zdK=DnHsX6DVCH@DBEdU|f$9wuZ8%8n}tX(3n^kxR%zvVb(f8x&uI zUEd671FPS08NL%T51{#C>%HOZ)YK$2!ur3!b1YCY@5I|RV}OM^4b74-2VA%X&b}hUtP`)szn7UgQi(3uUose zWavXd-56MFk;-fLgo1HeJ5<)Spj8{hckIX8ZC=|0>!_yt3yNu~nq`}j zWFi>pj7K8T&R7%{ETCkw6+_96qJ2ezA+#YTO{tiJx{)_2X;XJ^7t+AU(W+w6NNgON zXLa2GvsX+tU8V*_6)jgX+-B_&CYhB*zzzV-wkRf6 z=kkV{<#n2Fn1fhb(efrT<-kLT9e7>Bi2;uFwJRu?Cbm;$q)$G ztCr1l!PXh7!wIaXgLbl0Zq(Jq4a}(Kd90+wS8{-PyELvGTGGzImb|9+ng&`ny5IaL_|0xTubFO_83`skli{$`DS_vdz+bNM zhl1eHqlsWRl9Zw`NlJ!e$#^VA34Qc%#q*mTfZ-sp<57}@qr}t=>N^Yhi~%7lyko3d zQnZ{>Mjl7IP%tb7BZ2X8h;!!y03Srf%``S{0zAax;Z^V)gODMoj<5*WIs(#ZtFEB# zQ48r%I!%XVMZ*@!IxFl@QL7XRphACME#%THK4o>5g7kbrmEmBe(FAa7m11esCg_M%6*;*!e$VQ&>O)`+cv`V)Y41U za^4x?S~24PN+;B~48qc7HLGhmYP|00s>LB_*I&>TGbVYb%Rz7$l4rqkc?h0>0WUos zQxS-BEV^7$)m(bGIB0k!yJ>SQcu-a7Wz{oY2Vssy4pp?_G+4b^sWHt0Q4pQcb$WSl z?*?9buC>+5HH@8A3PK##;+EqeoJ*8CVj4<14Hp!+5y7fjHx{=w*X9uv;k$g!Jphwl z)+iKa1Q$ur=L1?mKiv3KD>Cq`y_+_-a`!5RmZo8h zcM06Ixs^)~dT2$V?Z6Q#hhssAvhg;~MLUR*Ap92?hhLisu@oa@ z8NA;EKOoEaBQn4Q1lV5(*a6T6@D}{w{2ahn0JZ=u1Ngg-koy5j05U)ez$4Ini`4~r z`kkpM_#t~9{=U72)xm>Y3gDR~sKZ#ki8KPx;*+uNUD`)8>bDvI)dMl)N`OlM-0KV# zz`x#VvjF9`0$>{~_{_ua#Q5F@JUK_-ZH$h6`vI`6XvyOfZlz&Cjg-f2%l$SL5v@;y2ybbQW!FM@t;X9w@iz_;1rU4-ND18^M{!@J8_ z1AYhPolkjS$qB^W6n~tmH^!wl@KyW`Q78%ZS^r9bwk_Yy5hJYrXow=+YEkXIb`uI z6vq!&OyUUi$O!Nqb@b`9yGGz;u_zg0{ho60I_DK_V>((U^m|+`P}n*%+b~<7wwI=rTYqS z-0vtEZ3%DmxCY$rT3}UBr$*pGt#STg=TkfJ!y8{O9KYiV4E6Y*RX~-g)&=|2O0fg#?#6TM8G+JH>2km{g}Yd@r_(2*qEy@ zocEVtIM=r-@N=B=A7k_&>-4n1&vDN0UuZGne#5ev;TATHbN;G8=QyVyWAy8I2af$g zs~FDt69S#%oL*vd-rq5SpW_mj2T%CS?b>fh64b8aI4O=Y+xbDihNU5}wRN|A0MII; zs{u9x6ael3I12D0fL%Dk+N}k`)N=S(7E$8y{*Giendp!bxon3L3Mn1YNTf3qR->_) zDy=5>bki5Bs}Spv^|K1lGvxkv4lM6pwV3!{-W2SElVOtFKhe}R1U1!v-o3(vr(J~h zX#Qt?RzqN8&A^$rLMObje9co&-pV==+T(Pz5FZKopOYKO0yqKYk;AROmZ`kflhzXv zp&g)A<+Imc@%o7?Qh$CoG4}9_m!-nHw=T-wwlcNl*na(m>)TRyu01|9^~AE*PM z-}nCIDcYyd56G8+QH2kZ<@}VeH2v zdHKx2@88~2E?XUOx6jrC&?*%m=!xUiBKoP z&b)T~zBB*c&`u_*+4b@zcP-o7m1&UM$?;Ax(N;2J1dL|gVPC;J}lfAm1=hbeel(S7Fh zfz)Td zs}?_gaOB=m6?QmtAd|iqZ;OvVR9v-q`N_Bc_|lgh4rGS)yfFXQp9p9A`(sK+G8u|> zNJ=Eqkw|302`X_Vlk80767d-NKl)+~WCr=@;VuWb8UT+(+&nh`*o7l(o<9zRSJYc7 z_$e(-?~02_dpCWtn#>>vPhq@53_@-q7C(zWo%bY*vWT{==O)r`x^@C%JvXsdUS?ZYJvXtQn@Dqj>$!=L ziCxc4tmkx}PdZH@&yQV`wQa}L5B zi*$UI_6}Ac3Zi)yqI-^c?YY*ro}1{%nilgGyvtCFLs*O1d2LT-Aph3Rb2Pj<)Z!3y zsOKi~zx?BQix+ev*f}}gMR1XX+5dnRFr78z73-$Wt=#F%Ca+vKZEod?*;-!dwKxPF z>bZ&VcQf_eMB(p*;Ky$KrM#Y-Xnixm?*mvcS8dvp)N>Q-xruK3sOKiu&P}YsceND# He}McKLgno% literal 15578 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 Z<~^}{akP_Gfd7X)rgpghkJJCt{9m35nk@hT