Repository: mie-lab/trackintel
Pull request #234 (2021-06-07 12:33:44)

CLN: A variety of smaller consistensy issues
fixes  #228

henrymartin1: I tried to simplify the review by creating a commit for every point from #228 (I just noticed that the issue number in the commit names is wrong ;-) )

codecov[bot]: # [Codecov](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab) Report
> Merging [#234](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab) (260f2ea) into [master](https://codecov.io/gh/mie-lab/trackintel/commit/8a005014e395416f145042dc87a03808ff5741d2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab) (8a00501) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/mie-lab/trackintel/pull/234/graphs/tree.svg?width=650&height=150&src=pr&token=ITDZEEE1MO&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab)](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab)

```diff
@@           Coverage Diff           @@
##           master     #234   +/-   ##
=======================================
  Coverage   94.76%   94.77%           
=======================================
  Files          37       37           
  Lines        1548     1550    +2     
  Branches      259      260    +1     
=======================================
+ Hits         1467     1469    +2     
  Misses         42       42           
  Partials       39       39           
```


| [Impacted Files](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab) | Coverage Δ | |
|---|---|---|
| [trackintel/preprocessing/triplegs.py](https://codecov.io/gh/mie-lab/trackintel/pull/234/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab#diff-dHJhY2tpbnRlbC9wcmVwcm9jZXNzaW5nL3RyaXBsZWdzLnB5) | `91.91% <ø> (-0.06%)` | :arrow_down: |
| [trackintel/analysis/label.py](https://codecov.io/gh/mie-lab/trackintel/pull/234/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab#diff-dHJhY2tpbnRlbC9hbmFseXNpcy9sYWJlbC5weQ==) | `97.22% <100.00%> (ø)` | |
| [trackintel/io/dataset\_reader.py](https://codecov.io/gh/mie-lab/trackintel/pull/234/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab#diff-dHJhY2tpbnRlbC9pby9kYXRhc2V0X3JlYWRlci5weQ==) | `96.00% <100.00%> (-0.04%)` | :arrow_down: |
| [trackintel/model/triplegs.py](https://codecov.io/gh/mie-lab/trackintel/pull/234/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab#diff-dHJhY2tpbnRlbC9tb2RlbC90cmlwbGVncy5weQ==) | `100.00% <100.00%> (ø)` | |
| [trackintel/preprocessing/positionfixes.py](https://codecov.io/gh/mie-lab/trackintel/pull/234/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab#diff-dHJhY2tpbnRlbC9wcmVwcm9jZXNzaW5nL3Bvc2l0aW9uZml4ZXMucHk=) | `96.00% <100.00%> (-0.03%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab). Last update [8a00501...260f2ea](https://codecov.io/gh/mie-lab/trackintel/pull/234?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mie-lab).


Patch:
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a16ce8b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+* linguist-vendored
+*.py linguist-vendored=false
\ No newline at end of file
diff --git a/docs/modules/io.rst b/docs/modules/io.rst
index c1091f3..d557b4e 100644
--- a/docs/modules/io.rst
+++ b/docs/modules/io.rst
@@ -87,4 +87,10 @@ Predefined dataset readers
 ==========================
 We also provide functionality to parse well-known datasets directly into the trackintel framework.
 
+Geolife
+-----------
+We support easy parsing of the Geolife dataset including available mode labels.
+
 .. autofunction:: trackintel.io.dataset_reader.read_geolife
+
+.. autofunction:: trackintel.io.dataset_reader.geolife_add_modes_to_triplegs
diff --git a/trackintel/analysis/label.py b/trackintel/analysis/label.py
index 9f90f8c..6ee8516 100644
--- a/trackintel/analysis/label.py
+++ b/trackintel/analysis/label.py
@@ -1,10 +1,11 @@
 import datetime
+
 import numpy as np
 
 from trackintel.geogr.distances import check_gdf_crs, calculate_haversine_length
 
 
-def create_activity_flag(staypoints, method="time_threshold", time_threshold=5.0, activity_column_name="activity"):
+def create_activity_flag(staypoints, method="time_threshold", time_threshold=15.0, activity_column_name="activity"):
     """
     Add a flag whether or not a staypoint is considered an activity.
 
@@ -17,7 +18,7 @@ def create_activity_flag(staypoints, method="time_threshold", time_threshold=5.0
 
         - 'time_threshold' : All staypoints with a duration greater than the time_threshold are considered an activity.
 
-    time_threshold : float, default = 5 (minutes)
+    time_threshold : float, default = 15 (minutes)
         The time threshold for which a staypoint is considered an activity in minutes. Used by method 'time_threshold'
 
     activity_column_name : str , default = 'activity'
@@ -30,7 +31,7 @@ def create_activity_flag(staypoints, method="time_threshold", time_threshold=5.0
 
     Examples
     --------
-    >>> stps  = stps.as_staypoints.create_activity_flag(method='time_threshold', time_threshold=5)
+    >>> stps  = stps.as_staypoints.create_activity_flag(method='time_threshold', time_threshold=15)
     >>> print(stps['activity'])
     """
     if method == "time_threshold":
diff --git a/trackintel/io/dataset_reader.py b/trackintel/io/dataset_reader.py
index 201c958..9f3d98e 100644
--- a/trackintel/io/dataset_reader.py
+++ b/trackintel/io/dataset_reader.py
@@ -9,6 +9,7 @@ import numpy as np
 import pandas as pd
 from shapely.geometry import Point
 from sklearn.neighbors import NearestNeighbors
+from tqdm import tqdm
 
 FEET2METER = 0.3048
 
@@ -17,7 +18,7 @@ CRS_WGS84 = "epsg:4326"
 from trackintel.preprocessing.util import calc_temp_overlap
 
 
-def read_geolife(geolife_path):
+def read_geolife(geolife_path, print_progress=False):
     """
     Read raw geolife data and return trackintel positionfixes.
 
@@ -28,20 +29,27 @@ def read_geolife(geolife_path):
     geolife_path: str
         path to the directory with the geolife data
 
+    print_progress: Bool, default False
+        Show per-user progress if set to True.
+
     Returns
     -------
     gdf: GeoDataFrame (as trackintel positionfixes)
         Contains all loaded geolife positionfixes
 
     labels: dict
-        Dictionary with the available (optional) mode labels.
+        Dictionary with the available mode labels.
 
     Notes
     -----
-    The geopandas dataframe has the following columns and datatype: 'lat': float64, Latitude WGS84; 'lon': float64, Latitude WGS84; 'elevation': float64, in meters;
-    'tracked_at': datetime64[ns]; 'user_id': int64; 'geom': geopandas/shapely geometry; 'accuracy': None;
+    The geopandas dataframe has the following columns and datatype: 'lat': float64, Latitude WGS84;
+    'lon': float64, Longitude WGS84; 'elevation': float64, in meters; 'tracked_at': datetime64[ns];
+    'user_id': int64; 'geom': geopandas/shapely geometry; 'accuracy': None;
 
+    For some users, travel mode labels are provided as .txt file. These labels are read and returned as label dictionary.
     The label dictionary contains the user ids as keys and DataFrames with the available labels as values.
+    Labels can be added to each user at the tripleg level, see
+    :func:`trackintel.io.dataset_reader.geolife_add_modes_to_triplegs` for more details.
 
     The folder structure within the geolife directory needs to be identical with the folder structure
     available from the official download. The means that the top level folder (provided with 'geolife_path')
@@ -52,17 +60,22 @@ def read_geolife(geolife_path):
     | │   ├── Trajectory
     | │   │   ├── 20081023025304.plt
     | │   │   ├── 20081024020959.plt
-    | │   │   └── 20081026134407.plt
+    | │   │   ├── 20081026134407.plt
+    | │   │   └── ...
     | ├── 001
     | │   ├── Trajectory
     | │   │   └── ...
+    | │   ...
+    | ├── 010
+    | │   ├── labels.txt
+    | │   ├── Trajectory
+    | │   │   └── ...
     | └── ...
 
     the geolife dataset as it can be downloaded from:
 
     https://www.microsoft.com/en-us/research/publication/geolife-gps-trajectory-dataset-user-guide/
 
-
     References
     ----------
     [1] Yu Zheng, Lizhu Zhang, Xing Xie, Wei-Ying Ma. Mining interesting locations and travel sequences from
@@ -77,7 +90,8 @@ def read_geolife(geolife_path):
 
     Example
     ----------
-    >>> geolife_pfs, labels = read_geolife(os.path.join('downloads', 'Geolife Trajectories 1.3'))
+    >>> from trackintel.io.dataset_reader import read_geolife
+    >>> pfs, mode_labels = read_geolife(os.path.join('downloads', 'Geolife Trajectories 1.3'))
     """
     geolife_path = os.path.join(geolife_path, "*")
     user_folder = sorted(glob.glob(geolife_path))
@@ -88,7 +102,7 @@ def read_geolife(geolife_path):
     if len(user_folder) == 0:
         raise NameError("No folders found with working directory {} and path {}".format(os.getcwd(), geolife_path))
 
-    for user_folder_this in user_folder:
+    for user_folder_this in tqdm(user_folder, disable=not print_progress):
 
         # skip files
         if not os.path.isdir(user_folder_this):
@@ -115,8 +129,6 @@ def read_geolife(geolife_path):
             )
             raise ValueError(errmsg) from err
 
-        print("start importing geolife user_id: ", user_id)
-
         input_files = sorted(glob.glob(os.path.join(user_folder_this, "Trajectory", "*.plt")))
         df_list_days = []
 
@@ -145,7 +157,6 @@ def read_geolife(geolife_path):
         # concat all days of a user into a single dataframe
         df_user_this = pd.concat(df_list_days, axis=0, ignore_index=True)
         label_dict[user_id] = labels
-        print("finished user_id: ", user_id)
 
         df_list_users.append(df_user_this)
 
@@ -189,6 +200,14 @@ def geolife_add_modes_to_triplegs(
     -------
     tpls : GeoDataFrame (as trackintel triplegs)
         triplegs with mode labels.
+
+    Example
+    ----------
+    >>> from trackintel.io.dataset_reader import read_geolife, geolife_add_modes_to_triplegs
+    >>> pfs, mode_labels = read_geolife(os.path.join('downloads', 'Geolife Trajectories 1.3'))
+    >>> pfs, spts = pfs.as_positionfixes.generate_staypoints()
+    >>> pfs, tpls = pfs.as_positionfixes.generate_triplegs(spts)
+    >>> tpls = geolife_add_modes_to_triplegs(tpls, mode_labels)
     """
     tpls = tpls_in.copy()
     # temp time fields for nn query
diff --git a/trackintel/model/triplegs.py b/trackintel/model/triplegs.py
index f57ca41..f778cd0 100644
--- a/trackintel/model/triplegs.py
+++ b/trackintel/model/triplegs.py
@@ -103,6 +103,23 @@ class TriplegsAccessor(object):
         """
         return ti.preprocessing.filter.spatial_filter(self._obj, *args, **kwargs)
 
+    def generate_trips(self, *args, **kwargs):
+        """
+        Generate trips based on staypoints and triplegs.
+
+        See :func:`trackintel.preprocessing.triplegs.generate_trips`.
+        """
+        # if spts in kwargs: 'spts' can not be in args as it would be the first argument
+        if "stps_input" in kwargs:
+            return ti.preprocessing.triplegs.generate_trips(tpls_input=self._obj, **kwargs)
+        # if 'spts' no in kwargs it has to be the first argument in 'args'
+        else:
+            assert len(args) <= 1, (
+                "All arguments except 'stps_input' have to be given as keyword arguments. You gave"
+                f" {args[1:]} as positional arguments."
+            )
+            return ti.preprocessing.triplegs.generate_trips(stps_input=args[0], tpls_input=self._obj, **kwargs)
+
     def predict_transport_mode(self, *args, **kwargs):
         """
         Predict/impute the transport mode with which each tripleg was likely covered.
diff --git a/trackintel/preprocessing/positionfixes.py b/trackintel/preprocessing/positionfixes.py
index 46afbf9..54daa77 100644
--- a/trackintel/preprocessing/positionfixes.py
+++ b/trackintel/preprocessing/positionfixes.py
@@ -1,10 +1,9 @@
+import datetime
+
 import geopandas as gpd
 import numpy as np
 import pandas as pd
 from shapely.geometry import LineString, Point
-from sklearn.cluster import DBSCAN
-
-import datetime
 from tqdm import tqdm
 
 from trackintel.geogr.distances import haversine_dist
@@ -36,7 +35,8 @@ def generate_staypoints(
 
     dist_threshold : float, default 100
         The distance threshold for the 'sliding' method, i.e., how far someone has to travel to
-        generate a new staypoint. Units depend on the dist_func parameter.
+        generate a new staypoint. Units depend on the dist_func parameter. If 'distance_metric' is 'haversine' the
+        unit is in meters
 
     time_threshold : float, default 5.0 (minutes)
         The time threshold for the 'sliding' method in minutes.
@@ -354,7 +354,7 @@ def generate_triplegs(pfs_input, stps_input, method="between_staypoints", gap_th
         posfix_grouper = pfs.groupby("tripleg_id")
 
         tpls = posfix_grouper.agg(
-            {"user_id": ["mean"], "tracked_at": [min, max], "geom": list}
+            {"user_id": ["mean"], "tracked_at": [min, max], pfs.geometry.name: list}
         )  # could add a "number of pfs": can be any column "count"
 
         # prepare dataframe: Rename columns; read/set geometry/crs;
diff --git a/trackintel/preprocessing/staypoints.py b/trackintel/preprocessing/staypoints.py
index 16e2a09..dec9390 100644
--- a/trackintel/preprocessing/staypoints.py
+++ b/trackintel/preprocessing/staypoints.py
@@ -111,7 +111,9 @@ def generate_locations(
         else:
             ## generate user-location pairs with same geometries across users
             # get user-location pairs
-            ret_loc = temp_sp.dissolve(by=["user_id", "location_id"], as_index=False).drop(columns={"geom"})
+            ret_loc = temp_sp.dissolve(by=["user_id", "location_id"], as_index=False).drop(
+                columns={temp_sp.geometry.name}
+            )
             # get location geometries
             geom_df = temp_sp.dissolve(by=["location_id"], as_index=False).drop(columns={"user_id"})
             # merge pairs with location geometries
@@ -124,17 +126,17 @@ def generate_locations(
         # locations with only one staypoints is of type "Point"
         point_idx = ret_loc.geom_type == "Point"
         if not ret_loc.loc[point_idx].empty:
-            ret_loc.loc[point_idx, "center"] = ret_loc.loc[point_idx, "geom"]
+            ret_loc.loc[point_idx, "center"] = ret_loc.loc[point_idx, ret_loc.geometry.name]
         # locations with multiple staypoints is of type "MultiPoint"
         if not ret_loc.loc[~point_idx].empty:
-            ret_loc.loc[~point_idx, "center"] = ret_loc.loc[~point_idx, "geom"].apply(
+            ret_loc.loc[~point_idx, "center"] = ret_loc.loc[~point_idx, ret_loc.geometry.name].apply(
                 lambda p: Point(np.array(p)[:, 0].mean(), np.array(p)[:, 1].mean())
             )
 
         # extent is the convex hull of the geometry
         ret_loc["extent"] = None  # initialize
         if not ret_loc.empty:
-            ret_loc["extent"] = ret_loc["geom"].apply(lambda p: p.convex_hull)
+            ret_loc["extent"] = ret_loc[ret_loc.geometry.name].apply(lambda p: p.convex_hull)
             # convex_hull of one point would be a Point and two points a Linestring,
             # we change them into Polygon by creating a buffer of epsilon around them.
             pointLine_idx = (ret_loc["extent"].geom_type == "LineString") | (ret_loc["extent"].geom_type == "Point")
diff --git a/trackintel/preprocessing/triplegs.py b/trackintel/preprocessing/triplegs.py
index f599a38..45103be 100644
--- a/trackintel/preprocessing/triplegs.py
+++ b/trackintel/preprocessing/triplegs.py
@@ -1,4 +1,3 @@
-import copy
 import datetime
 
 import numpy as np
@@ -80,7 +79,12 @@ def generate_trips(stps_input, tpls_input, gap_threshold=15, print_progress=Fals
 
     Examples
     --------
+    >>> from trackintel.preprocessing.triplegs import generate_trips
     >>> staypoints, triplegs, trips = generate_trips(staypoints, triplegs)
+
+    trips can also be directly generated using the tripleg accessor
+    >>> staypoints, triplegs, trips = triplegs.as_triplegs.generate_trips(staypoints)
+
     """
     assert (
         "activity" in stps_input.columns


Test patch:
diff --git a/tests/analysis/test_label.py b/tests/analysis/test_label.py
index a6f3ec1..fdceefd 100644
--- a/tests/analysis/test_label.py
+++ b/tests/analysis/test_label.py
@@ -1,6 +1,7 @@
 import os
-import pandas as pd
+
 import numpy as np
+import pandas as pd
 import pytest
 
 import trackintel as ti
@@ -18,7 +19,7 @@ class TestCreate_activity_flag:
         activity_true = stps_test["activity"].copy()
         stps_test["activity"] = False
 
-        stps_test = stps_test.as_staypoints.create_activity_flag()
+        stps_test = stps_test.as_staypoints.create_activity_flag(method="time_threshold", time_threshold=5.0)
 
         pd.testing.assert_series_equal(stps_test["activity"], activity_true)
 
diff --git a/tests/io/test_dataset_reader.py b/tests/io/test_dataset_reader.py
index 93be32d..510d205 100644
--- a/tests/io/test_dataset_reader.py
+++ b/tests/io/test_dataset_reader.py
@@ -81,13 +81,26 @@ def impossible_matching_data():
 class TestReadGeolife:
     def test_loop_read(self):
         """Use read_geolife reader, store posfix as .csv, load them again."""
-        pfs, _ = read_geolife(os.path.join("tests", "data", "geolife"))
+        pfs, _ = read_geolife(os.path.join("tests", "data", "geolife"), print_progress=True)
         tmp_file = os.path.join("tests", "data", "positionfixes_test.csv")
         pfs.as_positionfixes.to_csv(tmp_file)
         pfs2 = ti.read_positionfixes_csv(tmp_file, index_col="id")[pfs.columns]
         os.remove(tmp_file)
         assert np.isclose(0, (pfs.lat - pfs2.lat).abs().sum())
 
+    def test_print_progress_flag(self, capsys):
+        """Test if the print_progress par controls the printing behavior"""
+        g_path = os.path.join("tests", "data", "geolife")
+        pfs, _ = read_geolife(g_path, print_progress=True)
+        captured_print = capsys.readouterr()
+        assert captured_print.err != ""
+
+        pfs, _ = read_geolife(g_path, print_progress=False)
+        captured_noprint = capsys.readouterr()
+        assert captured_noprint.err == ""
+
+        assert True
+
     def test_label_reading(self):
         """test data types of the labels returned by read_geolife"""
 
diff --git a/tests/preprocessing/test_triplegs.py b/tests/preprocessing/test_triplegs.py
index 40e3388..80e8279 100644
--- a/tests/preprocessing/test_triplegs.py
+++ b/tests/preprocessing/test_triplegs.py
@@ -3,6 +3,8 @@ import os
 import geopandas as gpd
 import numpy as np
 import pandas as pd
+import pytest
+from geopandas.testing import assert_geodataframe_equal
 from shapely.geometry import Point, LineString
 
 import trackintel as ti
@@ -63,6 +65,54 @@ class TestGenerate_trips:
         # test if generated trips are equal
         pd.testing.assert_frame_equal(trips_loaded, trips)
 
+    def test_accessor(self):
+        """Test if the accessor leads to the same results as the explicit function."""
+        # load pregenerated trips
+        trips_loaded = ti.read_trips_csv(os.path.join("tests", "data", "geolife_long", "trips.csv"), index_col="id")
+
+        # prepare data
+        pfs, _ = ti.io.dataset_reader.read_geolife(os.path.join("tests", "data", "geolife_long"))
+        pfs, stps = pfs.as_positionfixes.generate_staypoints(method="sliding", dist_threshold=25, time_threshold=5)
+        stps = stps.as_staypoints.create_activity_flag(time_threshold=15)
+        pfs, tpls = pfs.as_positionfixes.generate_triplegs(stps)
+
+        # generate trips using the explicit function import
+        stps_expl, tpls_expl, trips_expl = ti.preprocessing.triplegs.generate_trips(stps, tpls, gap_threshold=15)
+
+        # generate trips using the accessor
+        stps_acc, tpls_acc, trips_acc = tpls.as_triplegs.generate_trips(stps, gap_threshold=15)
+
+        # test if generated trips are equal
+        pd.testing.assert_frame_equal(trips_expl, trips_acc)
+        assert_geodataframe_equal(stps_expl, stps_acc)
+        assert_geodataframe_equal(tpls_expl, tpls_acc)
+
+    def test_accessor_arguments(self):
+        """Test if the accessor is robust to different ways to receive arguments"""
+        # load pregenerated trips
+        trips_loaded = ti.read_trips_csv(os.path.join("tests", "data", "geolife_long", "trips.csv"), index_col="id")
+
+        # prepare data
+        pfs, _ = ti.io.dataset_reader.read_geolife(os.path.join("tests", "data", "geolife_long"))
+        pfs, stps = pfs.as_positionfixes.generate_staypoints(method="sliding", dist_threshold=25, time_threshold=5)
+        stps = stps.as_staypoints.create_activity_flag(time_threshold=15)
+        pfs, tpls = pfs.as_positionfixes.generate_triplegs(stps)
+
+        # accessor with only arguments (not allowed)
+        with pytest.raises(AssertionError):
+            _, _, _ = tpls.as_triplegs.generate_trips(stps, 15)
+
+        # accessor with only keywords
+        stps_1, tpls_1, trips_1 = tpls.as_triplegs.generate_trips(stps_input=stps, gap_threshold=15)
+
+        # accessor with mixed arguments/keywords
+        stps_2, tpls_2, trips_2 = tpls.as_triplegs.generate_trips(stps, gap_threshold=15)
+
+        # test if generated trips are equal (1,2)
+        assert_geodataframe_equal(stps_1, stps_2)
+        assert_geodataframe_equal(tpls_1, tpls_2)
+        pd.testing.assert_frame_equal(trips_1, trips_2)
+
     def test_generate_trips_missing_link(self):
         """Test nan is assigned for missing link between stps and trips, and tpls and trips."""
         # create trips from geolife (based on positionfixes)