Skip to content

Commit b943213

Browse files
Merge pull request #48 from UMDBPP/develop
add sorting, fix slicing, add dataframe property
2 parents 8a73c66 + 6ad243f commit b943213

File tree

4 files changed

+50
-6
lines changed

4 files changed

+50
-6
lines changed

packetraven/structures.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import Any, Iterable, List, Union
22

3+
from numpy import int32, int64
4+
35

46
class DoublyLinkedList:
57
"""
@@ -149,6 +151,12 @@ def count(self, value) -> int:
149151

150152
return sum([1 for node_value in self if node_value == value])
151153

154+
def sort(self):
155+
sorted_values = sorted(self)
156+
self.head = None
157+
self.tail = None
158+
self.extend(sorted_values)
159+
152160
@property
153161
def difference(self) -> [Any]:
154162
"""
@@ -216,12 +224,16 @@ def _remove_node(self, node: Node):
216224
self.head = node.next_node
217225

218226
def __getitem__(self, index: Union[int, Iterable[int], slice]) -> Union[Any, List[Any]]:
219-
if isinstance(index, int):
227+
if isinstance(index, int) or isinstance(index, int32) or isinstance(index, int64):
220228
return self._node_at_index(index).value
221229
elif isinstance(index, Iterable):
222-
return [self.__getitem__(value) for value in index]
230+
return self.__class__([self.__getitem__(value) for value in index])
223231
elif isinstance(index, slice):
224-
return self.__getitem__(range(*(value for value in (index.start, index.stop, index.step) if value is not None)))
232+
slice_parameters = [value for value in (index.start, index.stop, index.step) if value is not None]
233+
if all(slice_parameter is None for slice_parameter in slice_parameters):
234+
return self
235+
else:
236+
return self.__getitem__(range(*slice_parameters))
225237
else:
226238
raise ValueError(f'unrecognized index: {index}')
227239

packetraven/tracks.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from datetime import datetime, timedelta
2-
from typing import Union
2+
from typing import Iterable, Union
33

44
from dateutil.parser import parse as parse_date
55
import numpy
6+
from pandas import DataFrame
67
from pyproj import CRS
78

89
from .model import SECONDS_TO_GROUND
@@ -36,6 +37,13 @@ def append(self, packet: LocationPacket):
3637
packet.transform_to(self.crs)
3738
self.packets.append(packet)
3839

40+
def extend(self, packets: [LocationPacket]):
41+
for packet in packets:
42+
self.append(packet)
43+
44+
def sort(self):
45+
self.packets.sort()
46+
3947
@property
4048
def times(self) -> numpy.ndarray:
4149
return numpy.array([packet.time for packet in self.packets], dtype=numpy.datetime64)
@@ -137,8 +145,13 @@ def length(self) -> float:
137145
""" total length of the packet track over the ground """
138146
return sum([distance.overground for distance in self.packets.difference])
139147

140-
def __getitem__(self, index: Union[int, slice]) -> LocationPacket:
141-
return self.packets[index]
148+
def __getitem__(self, index: Union[int, Iterable[int], slice]) -> Union[LocationPacket, 'LocationPacketTrack']:
149+
if isinstance(index, int):
150+
return self.packets[index]
151+
elif isinstance(index, Iterable) or isinstance(index, slice):
152+
return self.__class__(self.name, self.packets[index], self.crs)
153+
else:
154+
raise ValueError(f'unrecognized index: {index}')
142155

143156
def __iter__(self):
144157
return iter(self.packets)
@@ -158,6 +171,22 @@ def __eq__(self, other) -> bool:
158171
def __str__(self) -> str:
159172
return str(list(self))
160173

174+
@property
175+
def dataframe(self) -> DataFrame:
176+
return DataFrame({
177+
'name': [self.name for _ in range(len(self))],
178+
'times': self.times,
179+
'x': self.coordinates[:, 0],
180+
'y': self.coordinates[:, 1],
181+
'z': self.coordinates[:, 2],
182+
'intervals': self.intervals,
183+
'overground_distances': self.overground_distances,
184+
'ascents': self.ascents,
185+
'ascent_rates': self.ascent_rates,
186+
'ground_speeds': self.ground_speeds,
187+
'cumulative_overground_distances': self.cumulative_overground_distances,
188+
})
189+
161190

162191
class BalloonTrack(LocationPacketTrack):
163192
def __init__(self, name: str, packets: [LocationPacket] = None, crs: CRS = None):

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
'aprslib',
8181
'haversine',
8282
'numpy>=1.20.0',
83+
'pandas',
8384
'pyserial',
8485
'geojson',
8586
'fastkml',

tests/test_packets.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ def test_append():
8989
assert track[0] is packet_1
9090
assert track[1] is packet_2
9191
assert track[-1] is packet_2
92+
assert track[:] == track
93+
assert track[1:] == APRSTrack(track.name, track.packets[1:], track.crs)
9294

9395

9496
def test_values():

0 commit comments

Comments
 (0)