From 1405d498873d6da521cb81ba1439ba753e236b71 Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 19:42:04 +0100 Subject: [PATCH 1/7] Remove rpy2 support --- .travis.yml | 2 +- docs/requirements.txt | 1 - docs/source/conf.py | 2 +- docs/source/rinterface.rst | 65 ---------------- traja/rutils.py | 156 ------------------------------------- 5 files changed, 2 insertions(+), 224 deletions(-) delete mode 100644 docs/source/rinterface.rst delete mode 100644 traja/rutils.py diff --git a/.travis.yml b/.travis.yml index b87c5109..fd61cc27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ install: script: - cd docs && make doctest && cd .. - - py.test . --cov-report term --cov=traja --ignore tests/test_rutils.py + - py.test . --cov-report term --cov=traja after_success: - codecov diff --git a/docs/requirements.txt b/docs/requirements.txt index 932d4323..e05c00c7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -14,4 +14,3 @@ pytest pytest-cov codecov readline -rpy2 diff --git a/docs/source/conf.py b/docs/source/conf.py index 651e52a9..49cf67e4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -68,7 +68,7 @@ "doc_module": ("traja",), "reference_url": { "numpy": "http://docs.scipy.org/doc/numpy", - "scipy": "http://docs.scipy.org/doc/scipy/reference", + # "scipy": "http://docs.scipy.org/doc/scipy/reference", "geopandas": "https://geopandas.readthedocs.io/en/latest/", }, "sphinx_gallery": None, diff --git a/docs/source/rinterface.rst b/docs/source/rinterface.rst deleted file mode 100644 index 9ab6e9ec..00000000 --- a/docs/source/rinterface.rst +++ /dev/null @@ -1,65 +0,0 @@ -R interface -=========== - -`rpy2` allows connecting R packages to Python. Install rpy2 with ``pip install rpy2`` or ``conda install -c r rpy2``. - -.. code-block:: python - - import traja - from traja import rutils - - df = traja.generate() - -Convert to adehabitat class `ltraj` for further analysis with R ---------------------------------------------------------------- - -`adehabitat `_ -is a widely used R library for animal tracking and trajectory -analysis. - -.. code-block:: python - - ltraj = rutils.to_ltraj(df) - rutils.plot_ltraj(ltraj) - -.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/source/_static/ltraj_plot.png - -Convert to `trajr` object -------------------------- - -`trajr `_ is another widely used R package. -Convert a `TrajaDataFrame` to `trajr` dataframe with: - -.. code-block:: python - - # Convert to trajr trajectory - traj = rutils.to_trajr(df) - - # Plot trajectory using trajr backend - traj.plot_Trajectory(traj) - - -Perform further analysis in Python ----------------------------------- -Data frame is stored in first index. - -.. code-block:: python - - print(ltraj.head()) - -Out:: - - x y date dx dy dist dt R2n - 0 0.0000000 0.000000 1 1.341849037 1.629900330 2.111193 1 0.000000 - 1 1.3418490 1.629900 2 1.022740115 1.923497375 2.178495 1 4.457134 - 2 2.3645892 3.553398 3 -0.001297666 1.915536596 1.915537 1 18.217917 - 3 2.3632915 5.468934 4 -1.820040071 0.878444059 2.020943 1 35.494389 - 4 0.5432514 6.347378 5 -1.810551702 -0.952063825 2.045611 1 40.584334 - 5 -1.2673003 5.395315 6 -2.040275034 0.009247058 2.040296 1 30.715469 - abs.angle rel.angle - 0 0.8820262 NA - 1 1.0821048 0.2000786 - 2 1.5714738 0.4893690 - 3 2.6919204 1.1204466 - 4 -2.6574859 0.9337790 - 5 3.1370604 -0.4886389 diff --git a/traja/rutils.py b/traja/rutils.py deleted file mode 100644 index 01625fa3..00000000 --- a/traja/rutils.py +++ /dev/null @@ -1,156 +0,0 @@ -try: - import rpy2 -except ImportError: - raise ImportError( - "Python package rpy2 is required for this. Install it with" - "\n" - "pip install rpy2" - "" - ) -import rpy2.robjects.packages as rpackages - -try: - import rpy2.robjects.pandas2ri as rpandas -except ModuleNotFoundError as e: - if "tzlocal" in e.msg: - raise ModuleNotFoundError( - e.msg + "\n Install tzlocal with `pip install tzlocal`." - ) - else: - raise ModuleNotFoundError(e) -from rpy2.robjects.packages import importr - - -__all__ = ["import_adehabitat", "import_trajr", "plot_ltraj", "to_trajr", "to_ltraj"] - - -rpandas.activate() - -ADEHABITAT_INSTALLED = False -TRAJR_INSTALLED = False - - -def import_adehabitat(suppress_messages=True): - global ADEHABITAT_INSTALLED - if not ADEHABITAT_INSTALLED: - utils = rpackages.importr("utils", suppress_messages=suppress_messages) - print("Importing adehabitat") - utils.chooseCRANmirror(ind=1) - utils.install_packages("adehabitatLT") - ADEHABITAT_INSTALLED = True - adehabitat = importr("adehabitatLT", suppress_messages=suppress_messages) - return adehabitat - - -def import_trajr(suppress_messages=True): - global TRAJR_INSTALLED - if not TRAJR_INSTALLED: - utils = rpackages.importr("utils", suppress_messages=suppress_messages) - print("Importing trajr") - utils.chooseCRANmirror(ind=1) - utils.install_packages("trajr") - TRAJR_INSTALLED = True - trajr = importr("trajr") - return trajr - - -def plot_ltraj(ltraj, id=1): - """Plot `ltraj` using R method.""" - adehabitat = import_adehabitat() - adehabitat.plot_ltraj(ltraj, id=1) - - -def to_trajr(trj): - """Convert trajectory to R `trajr` object. Default fps is 30. - - Args: - trajectory (:class:`~traja.TrajaDataFrame`): trajectory - - - Returns: - traj (:class:`rpy2.robjects.vectors.DataFrame`): column names are ['x', 'y', 'time', 'displacementTime', - 'polar', 'displacement'] - - .. doctest:: - - >>> import traja; from traja import rutils - >>> df = traja.TrajaDataFrame({'x':range(5),'y':range(5)}) - >>> trjr_df = rutils.to_trajr(df) # doctest: +SKIP - >>> [x for x in trjr_df.names] # doctest: +SKIP - ... - ['x', 'y', 'id', 'time', 'displacementTime', 'polar', 'displacement'] - - - """ - from traja.trajectory import _get_time_col - - trajr = import_trajr() - if "id" not in trj.__dict__.keys(): - trj["id"] = 0 - time_col = _get_time_col(trj) - if time_col == "index": - trj["time"] = trj.index - time_col = "time" - fps = trj.fps - spatial_units = trj.spatial_units or "m" - time_units = trj.time_units or "s" - - trj_rdf = rpandas.py2rpy(trj) - - trajr_trj = trajr.TrajFromCoords( - trj_rdf, - xCol="x", - yCol="y", - timeCol=time_col or rpy2.rinterface.NULL, - fps=fps or 30, - spatialUnits=spatial_units, - timeUnits=time_units, - ) - - return trajr_trj - - -def to_ltraj(trj, id=1, typeII=False): - """Convert trajectory to R `ltraj` object. - - Args: - trajectory (:class:`~traja.TrajaDataFrame`): trajectory - id (str, optional): id of animal/target - typeII (bool): contains datatime format time series (not yet supported) - - Returns: - ltraj (:class:`rpy2.robjects.vectors.ListVector`): first index (ie, ltraj[0]) is pandas DataFrame including - columns 'x', 'y', 'date', 'dx', 'dy', 'dist', 'dt', - 'R2n', 'abs.angle', 'rel.angle' - - .. doctest:: - - >>> import traja; from traja import rutils - >>> df = traja.TrajaDataFrame({'x':range(5),'y':range(5)}) - >>> ltraj = rutils.to_ltraj(df) # doctest: +SKIP - >>> print(ltraj[0]) # doctest: +SKIP - ... - x y date dx ... dt R2n abs.angle rel.angle - 0 0 0 1 1 ... 1 0.0 0.785398 NaN - 1 1 1 2 1 ... 1 2.0 0.785398 0.0 - 2 2 2 3 1 ... 1 8.0 0.785398 0.0 - 3 3 3 4 1 ... 1 18.0 0.785398 0.0 - 4 4 4 5 -2147483648 ... -2147483648 32.0 NaN NaN - - [5 rows x 10 columns] - - """ - adehabitat = import_adehabitat() - - df = trj[["x", "y"]] - - if typeII: - raise NotImplementedError( - "datetime series not yet implemented for this method." - ) - # FIXME: Add date converted from rpy2.robjects.POSIXct - # date = None - # ltraj = adehabitat.as_ltraj(df, id=id, date=date, typeII=True) # Doesn't work - else: - ltraj = adehabitat.as_ltraj(df, id=id, typeII=False)[0] - return ltraj From 4b3d885051f6c61874c803730967b068effc7e3b Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 19:42:51 +0100 Subject: [PATCH 2/7] Remove rpy2 support --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index fd61cc27..9d2625f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ dist: xenial language: python python: - - '3.6' - '3.7' + - '3.8' git: depth: false @@ -18,9 +18,6 @@ cache: pip before_install: - sudo apt-get update - - sudo mkdir -p /usr/local/lib/R/site-library - - echo 'R_LIBS=/usr/local/lib/R/library:/usr/local/lib/R/site-library/' > ~/.Renviron - - sudo chmod 2777 /usr/local/lib/R/site-library install: - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh From 1d1ac518d52b521349963d80ef0bd2095d2c202c Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 19:43:16 +0100 Subject: [PATCH 3/7] Remove rpy2 support --- environment.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/environment.yml b/environment.yml index ca6af143..fc04e6ab 100644 --- a/environment.yml +++ b/environment.yml @@ -2,7 +2,6 @@ name: traja channels: - conda-forge - pytorch - - r dependencies: - ipython - pytorch-cpu @@ -17,5 +16,3 @@ dependencies: - scipy - sphinx - pillow - - r-essentials - - r-base From 5e87c9c2cb4826ea6b01a6bc35743b2d2b4a3a83 Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 19:43:43 +0100 Subject: [PATCH 4/7] Remove rpy2 support --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 58541cee..2561083d 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def find_version(*file_paths): requirements = ["matplotlib", "pandas", "numpy", "shapely", "scipy", "tzlocal"] -extras_requirements = {"all": ["torch", "rpy2", "tzlocal", "fastdtw"]} +extras_requirements = {"all": ["torch", "tzlocal", "fastdtw"]} this_dir = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(this_dir, "README.rst"), encoding="utf-8") as f: From 6005fc101e64ab77e02e7804d368618b4353859c Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 19:44:05 +0100 Subject: [PATCH 5/7] Remove rpy2 support --- traja/tests/test_rutils.py | 45 -------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 traja/tests/test_rutils.py diff --git a/traja/tests/test_rutils.py b/traja/tests/test_rutils.py deleted file mode 100644 index 55918a0b..00000000 --- a/traja/tests/test_rutils.py +++ /dev/null @@ -1,45 +0,0 @@ -import warnings - -import numpy as np -import numpy.testing as npt -from rpy2 import rinterface -from rpy2.rinterface import RRuntimeWarning - -import traja -from traja import rutils - - -warnings.filterwarnings("ignore", category=RRuntimeWarning, module="rpy2") -warnings.filterwarnings("ignore", category=UserWarning, module="rpy2") - - -df = traja.generate(n=20) - - -def test_import_adehabitat(): - rutils.import_adehabitat(suppress_messages=True) - - -def test_import_trajr(): - rutils.import_trajr(suppress_messages=True) - - -def test_to_trajr(): - trjr = rutils.to_trajr(df) - assert "x" in trjr - assert "y" in trjr - assert "time" in trjr - assert "polar" in trjr - assert "displacement" in trjr - actual = trjr.x[:3].values - expected = np.array([0.0, 1.162_605_74, 1.861_836_8]) - - npt.assert_allclose(actual, expected) - - -def test_to_ltraj(): - ltraj = rutils.to_ltraj(df) - rdataframe = ltraj - assert "x" in rdataframe - assert "y" in rdataframe - assert len(rdataframe) == 20 From 2ebd9cc2cd2a22301ede730d59ec9182b4b89b8e Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Sat, 2 Jan 2021 20:39:05 +0100 Subject: [PATCH 6/7] Fix actogram plot and tests --- traja/plotting.py | 14 +++++++++++--- traja/tests/test_plotting.py | 13 ++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/traja/plotting.py b/traja/plotting.py index da508e77..87832ed5 100644 --- a/traja/plotting.py +++ b/traja/plotting.py @@ -891,22 +891,29 @@ def _process_after_plot_args(**after_plot_args): def color_dark( - series: pd.Series, ax: matplotlib.axes.Axes, start: int = 19, end: int = 7 + series: pd.Series, ax: matplotlib.axes.Axes = None, start: int = 19, end: int = 7 ): """Color dark phase in plot.""" assert is_datetime_or_timedelta_dtype( series.index ), f"Series must have datetime index but has {type(series.index)}" + if not ax: + ax = plt.gca() + + # get boundaries for dark times dark_mask = (series.index.hour >= start) | (series.index.hour < end) run_values, run_starts, run_lengths = find_runs(dark_mask) + # highlighting for idx, is_dark in enumerate(run_values): if is_dark: start = run_starts[idx] end = run_starts[idx] + run_lengths[idx] - 1 ax.axvspan(series.index[start], series.index[end], alpha=0.5, color="gray") + return ax + def find_runs(x: pd.Series) -> (np.ndarray, np.ndarray, np.ndarray): """Find runs of consecutive items in an array. @@ -921,7 +928,6 @@ def find_runs(x: pd.Series) -> (np.ndarray, np.ndarray, np.ndarray): # handle empty array if n == 0: return np.array([]), np.array([]), np.array([]) - else: # find run starts loc_run_start = np.empty(n, dtype=bool) @@ -985,10 +991,12 @@ def plot_actogram( Curr Protoc Mouse Biol. 2015;5(3):271-281. Published 2015 Sep 1. doi:10.1002/9780470942390.mo140229 """ - after_plot_args, _ = _get_after_plot_args(**kwargs) + assert isinstance(series, pd.Series) assert is_datetime_or_timedelta_dtype( series.index ), f"Series must have datetime index but has {type(series.index)}" + + after_plot_args, _ = _get_after_plot_args(**kwargs) ax = series.plot(ax=ax) ax.set_ylabel(series.name) diff --git a/traja/tests/test_plotting.py b/traja/tests/test_plotting.py index 599ab319..2b86468e 100644 --- a/traja/tests/test_plotting.py +++ b/traja/tests/test_plotting.py @@ -20,15 +20,6 @@ def test_stylize_axes(): traja.plotting.stylize_axes(collection.axes) -def test_color_dark(): - df = traja.generate(n=10) - index = pd.DatetimeIndex(range(10)) - df.index = index - traja.plot(df, interactive=False) - ax = plt.gca() - traja.color_dark(df.x, ax) - - def test_sans_serif(): traja.plotting.sans_serif() @@ -64,8 +55,8 @@ def test_label_axes(): def test_plot_actogram(): - df = traja.generate(n=10) - index = pd.DatetimeIndex(range(10)) + df = traja.generate(n=1000) + index = pd.date_range("2018-01-01", periods=1000, freq="T") df.index = index activity = traja.calc_displacement(df) activity.name = "activity" From ed332649b572203d0ab605b06f255c9f3d425e52 Mon Sep 17 00:00:00 2001 From: Justin Shenk Date: Mon, 4 Jan 2021 16:04:45 +0100 Subject: [PATCH 7/7] Remove scipy docs link --- docs/source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 49cf67e4..98e15384 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -68,7 +68,6 @@ "doc_module": ("traja",), "reference_url": { "numpy": "http://docs.scipy.org/doc/numpy", - # "scipy": "http://docs.scipy.org/doc/scipy/reference", "geopandas": "https://geopandas.readthedocs.io/en/latest/", }, "sphinx_gallery": None,