1515
1616class NavData ():
1717 """gnss_lib_py specific class for handling data.
18- Uses numpy for speed combined with pandas like intuitive indexing
18+
19+ Uses numpy for speed combined with pandas like intuitive indexing.
20+
21+ Can either be initialized empty, with a csv file by setting
22+ ``csv_path``, a Pandas DataFrame by setting ``pandas_df`` or by a
23+ Numpy array by setting ``numpy_array``.
24+
25+ Parameters
26+ ----------
27+ csv_path : string
28+ Path to csv file containing data
29+ pandas_df : pd.DataFrame
30+ Data used to initialize NavData instance.
31+ numpy_array : np.ndarray
32+ Numpy array containing data used to initialize NavData
33+ instance.
34+ **kwargs : args
35+ Additional arguments (e.g. ``sep`` or ``header``) passed into
36+ ``pd.read_csv`` if csv_path is not None.
1937
2038 Attributes
2139 ----------
@@ -89,7 +107,8 @@ def from_pandas_df(self, pandas_df):
89107
90108 Parameters
91109 ----------
92- pandas_df : pd.DataFrame of data
110+ pandas_df : pd.DataFrame
111+ Data used to initialize NavData instance.
93112 """
94113
95114 if not isinstance (pandas_df , pd .DataFrame ):
@@ -112,54 +131,112 @@ def from_numpy_array(self, numpy_array):
112131 Parameters
113132 ----------
114133 numpy_array : np.ndarray
115- Numpy array containing data
134+ Numpy array containing data used to initialize NavData
135+ instance.
116136
117137 """
118138
139+
119140 if not isinstance (numpy_array , np .ndarray ):
120141 raise TypeError ("numpy_array must be np.ndarray" )
121142
143+
122144 self ._build_navdata ()
123145
146+ numpy_array = np .atleast_2d (numpy_array )
124147 for row_num in range (numpy_array .shape [0 ]):
125148 self [str (row_num )] = numpy_array [row_num ,:]
126149
127- def add (self , csv_path = None , pandas_df = None , numpy_array = None ):
128- """Add new timesteps to existing array
150+ def concat (self , navdata = None , axis = 1 , inplace = False ):
151+ """Concatenates second NavData instance by row or column.
152+
153+ Concatenates a second NavData instance to the existing NavData
154+ instance by either row or column.
155+
156+ Each type of data is included in a row, so adding new rows with
157+ ``axis=0``, means adding new types of data. Concat requires that
158+ the new NavData matches the length of the existing NavData. Row
159+ concatenation assumes the same ordering across both NavData
160+ instances (e.g. sorted by timestamp) and does not perform any
161+ matching/sorting itself.
162+
163+ You can also concatenate new columns ``axis=1``. If the row
164+ names of the new NavData instance don't match the row names of
165+ the existing NavData instance, the mismatched values will be
166+ filled with np.nan.
129167
130168 Parameters
131169 ----------
132- csv_path : string
133- Path to csv file containing data to add
134- pandas_df : pd.DataFrame
135- DataFrame containing data to add
136- numpy_array : np.ndarray
137- Array containing only numeric data to add
170+ navdata : gnss_lib_py.parsers.navdata.NavData
171+ Navdata instance to concatenate.
172+ axis : int
173+ Either add new rows (type) of data ``axis=0`` or new columns
174+ (e.g. timesteps) of data ``axis=1``.
175+ inplace : bool
176+ If False, will return new concatenated NavData instance.
177+ If True, will concatenate data to the current NavData
178+ instance.
179+
180+ Returns
181+ -------
182+ new_navdata : gnss_lib_py.parsers.navdata.NavData or None
183+ If inplace is False, returns NavData instance after
184+ concatenating specified data. If inplace is True, returns
185+ None.
186+
138187 """
139- old_row_num = len (self .map )
140- old_len = len (self )
141- new_data_cols = slice (old_len , None )
142- if numpy_array is not None :
143- if old_row_num == 0 :
144- self .from_numpy_array (numpy_array )
145- else :
146- if len (numpy_array .shape )== 1 :
147- numpy_array = np .reshape (numpy_array , [1 , - 1 ])
148- self .array = np .hstack ((self .array , np .empty_like (numpy_array ,
149- dtype = self .arr_dtype )))
150- self [:, new_data_cols ] = numpy_array
151- if csv_path is not None :
152- if old_row_num == 0 :
153- self .from_csv_path (csv_path )
154- else :
155- pandas_df = pd .read_csv (csv_path )
156- if pandas_df is not None :
157- if old_row_num == 0 :
158- self .from_pandas_df (pandas_df )
159- else :
160- self .array = np .hstack ((self .array , np .empty (pandas_df .shape ).T ))
161- for col in pandas_df .columns :
162- self [col , new_data_cols ] = np .asarray (pandas_df [col ].values )
188+
189+ if not isinstance (navdata ,NavData ):
190+ raise TypeError ("concat input data must be a NavData instance." )
191+
192+ if axis == 0 : # concatenate new rows
193+ if len (self ) != len (navdata ):
194+ raise RuntimeError ("concat input data must be same " \
195+ + "length to concatenate new rows." )
196+ if not inplace :
197+ new_navdata = self .copy ()
198+ for row in navdata .rows :
199+ new_row_name = row
200+ suffix = None
201+ while new_row_name in self .rows :
202+ if suffix is None :
203+ suffix = 0
204+ else :
205+ suffix += 1
206+ new_row_name = row + "_" + str (suffix )
207+ if inplace :
208+ self [new_row_name ] = navdata [row ]
209+ else :
210+ new_navdata [new_row_name ] = navdata [row ]
211+
212+ elif axis == 1 : # concatenate new columns
213+ new_navdata = NavData ()
214+ # get unique list of row names
215+ combined_rows = set (self .rows + navdata .rows )
216+
217+ for row in combined_rows :
218+ combined_row = np .array ([])
219+ # combine data from existing and new instance
220+ for data in [self , navdata ]:
221+ if row in data .rows :
222+ new_row = data [row ]
223+ elif len (data ) == 0 :
224+ continue
225+ else :
226+ # add np.nan for missing values
227+ new_row = np .empty ((len (data ),))
228+ new_row .fill (np .nan )
229+ combined_row = np .concatenate ((combined_row ,
230+ new_row ))
231+ new_navdata [row ] = combined_row
232+ if inplace :
233+ self .array = new_navdata .array
234+ self .map = new_navdata .map
235+ self .str_map = new_navdata .str_map
236+
237+ if inplace :
238+ return None
239+ return new_navdata
163240
164241 def where (self , key_idx , value , condition = "eq" ):
165242 """Return NavData where conditions are met for the given row
0 commit comments