From b1566045d3fbc13c9fa3f2d27e1fa46f1b8cf9f2 Mon Sep 17 00:00:00 2001 From: muschellij2 Date: Tue, 2 Jun 2026 12:13:52 -0400 Subject: [PATCH 1/5] added to readme --- R/aaa_utils.R | 4 + README.Rmd | 81 ++++--- README.md | 205 +++++++++++++++--- README_cache/gfm/__packages | 11 + ...k-2_dbaf97c3887afa912b9be6b97e070cab.RData | Bin 0 -> 4842 bytes ...unk-2_dbaf97c3887afa912b9be6b97e070cab.rdb | Bin 0 -> 3749 bytes ...unk-2_dbaf97c3887afa912b9be6b97e070cab.rdx | Bin 0 -> 220 bytes 7 files changed, 239 insertions(+), 62 deletions(-) create mode 100644 README_cache/gfm/__packages create mode 100644 README_cache/gfm/unnamed-chunk-2_dbaf97c3887afa912b9be6b97e070cab.RData create mode 100644 README_cache/gfm/unnamed-chunk-2_dbaf97c3887afa912b9be6b97e070cab.rdb create mode 100644 README_cache/gfm/unnamed-chunk-2_dbaf97c3887afa912b9be6b97e070cab.rdx diff --git a/R/aaa_utils.R b/R/aaa_utils.R index 858692c..6fb9705 100644 --- a/R/aaa_utils.R +++ b/R/aaa_utils.R @@ -3,6 +3,10 @@ oak_base = function() { stop( "Python package 'forest' is not installed in the active reticulate environment. ", "Install it yourself before calling walking functions that use forest.\n", + "If installation fails with \"clang++: error: unsupported option '-fopenmp'\", ", + "that is a Python toolchain/OpenMP problem, not a walking problem.\n", + "Use a Python environment where forest and numba/llvmlite already resolve cleanly, ", + "then point reticulate at that environment.\n", "See https://github.com/onnela-lab/forest/issues/293 and ", "https://github.com/numba/llvmlite/issues/1389." ) diff --git a/README.Rmd b/README.Rmd index 197c961..65d6271 100644 --- a/README.Rmd +++ b/README.Rmd @@ -11,6 +11,9 @@ knitr::opts_chunk$set( fig.path = "man/figures/README-", out.width = "100%" ) +reticulate::py_require( + "git+https://github.com/onnela-lab/forest@45fb41038bd46c25d9e6a4442aa74fa03b501317", + python_version = "3.11") ``` # walking @@ -33,10 +36,13 @@ devtools::install_github("muschellij2/walking") `walking` no longer tries to install `forest` for you. Install `forest` in your own Python environment first, then load `walking` from R. -If you hit the LLVM mismatch described in +If you hit `clang++: error: unsupported option '-fopenmp'` or the LLVM +mismatch described in [onnela-lab/forest#293](https://github.com/onnela-lab/forest/issues/293) and [numba/llvmlite#1389](https://github.com/numba/llvmlite/issues/1389), use a -Python environment where `forest` and its dependencies already resolve cleanly. +Python environment where `forest` and its dependencies already resolve cleanly, +then point `reticulate` at that environment with `use_condaenv()` or +`use_python()`. ## Example @@ -54,33 +60,56 @@ print(res) ## Potential Conflicts ### Running `forest` and [`stepcount`](https://github.com/jhuwit/stepcount). -The two Python modules (`forest` and `stepcount`) can be be installed in the same `conda` environment, but if they are not, this will lead to an error message. The options. One solution is to run them in two separate R sessions (recommended). +The two Python modules (`forest` and `stepcount`) can have different conflicts of python dependencies and python versions. You can do specific call-outs with `callr` to try to resolve this: -Alternatively, you can try to install `forest` in the `stepcount` conda environment, such as: +## Running Walking with Different Python Environments -```{r, eval = FALSE} -envname = "stepcount2" -stepcount::conda_create_stepcount(envname = envname) -# if you have RETICULATE_PYTHON set -stepcount::unset_reticulate_python() -stepcount::use_stepcount_condaenv(envname = envname) -``` - -and then run examples such as: +If you want to use both walking estimation from `forest` and `stepcount`, you can run them in separate R processes using `callr` to avoid Python package conflicts. +Here's how you can do it: -```{r, eval = FALSE} -library(walking) +```{r, cache = TRUE} +library(callr) library(stepcount) -envname = "stepcount2" - -# if you have RETICULATE_PYTHON set -stepcount::unset_reticulate_python() -stepcount::use_stepcount_condaenv(envname = envname) - csv_file = system.file("test_data_bout.csv", package = "walking") -x = readr::read_csv(csv_file) -colnames(x)[colnames(x) == "UTC time"] = "time" -res = find_walking(data = x) +data = readr::read_csv(csv_file) +colnames(data)[colnames(data) == "UTC time"] = "time" + +stepcount_callr = function(data, + ...) { + + reticulate::py_require("stepcount==3.11.0", python_version = "3.10") + sc <- reticulate::import("stepcount") + stepcount::stepcount_check() + + res = stepcount::stepcount(data, ...) + return(res) +} + +# 2. Run the isolated background R process +result <- callr::r( + func = stepcount_callr, + show = TRUE, + args = list(data = data) # Safely injects data into the process +) +head(result) + +forest_callr = function(data, + ...) { + reticulate::py_require( + "git+https://github.com/onnela-lab/forest@45fb41038bd46c25d9e6a4442aa74fa03b501317", + python_version = "3.11") + fr = reticulate::import("forest") + oak = fr$oak$base + oak + res = walking::estimate_steps_forest(data, ...) + return(res) +} + +# 2. Run the isolated background R process +fresult <- callr::r( + func = forest_callr, + show = TRUE, + args = list(data = data) # Safely injects data into the process +) +head(fresult) ``` - -Remember, however, best practices for Python is "Always create a separate virtual environment for each project" and sometimes one for each "goal". diff --git a/README.md b/README.md index cb5988f..32d0dec 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,17 @@ You can install the development version of walking from devtools::install_github("muschellij2/walking") ``` -`walking` no longer tries to install `forest` for you. Install `forest` in -your own Python environment first, then load `walking` from R. - -If you hit the LLVM mismatch described in -[onnela-lab/forest#293](https://github.com/onnela-lab/forest/issues/293) and -[numba/llvmlite#1389](https://github.com/numba/llvmlite/issues/1389), use a -Python environment where `forest` and its dependencies already resolve cleanly. +`walking` no longer tries to install `forest` for you. Install `forest` +in your own Python environment first, then load `walking` from R. + +If you hit `clang++: error: unsupported option '-fopenmp'` or the LLVM +mismatch described in +[onnela-lab/forest#293](https://github.com/onnela-lab/forest/issues/293) +and +[numba/llvmlite#1389](https://github.com/numba/llvmlite/issues/1389), +use a Python environment where `forest` and its dependencies already +resolve cleanly, then point `reticulate` at that environment with +`use_condaenv()` or `use_python()`. ## Example @@ -69,39 +73,168 @@ print(res) ### Running `forest` and [`stepcount`](https://github.com/jhuwit/stepcount). -The two Python modules (`forest` and `stepcount`) can be be installed in -the same `conda` environment, but if they are not, this will lead to an -error message. The options. One solution is to run them in two separate -R sessions (recommended). - -Alternatively, you can try to install `forest` in the `stepcount` conda -environment, such as: +The two Python modules (`forest` and `stepcount`) can have different +conflicts of python dependencies and python versions. You can do +specific call-outs with `callr` to try to resolve this: -``` r -envname = "stepcount2" -stepcount::conda_create_stepcount(envname = envname) -# if you have RETICULATE_PYTHON set -stepcount::unset_reticulate_python() -stepcount::use_stepcount_condaenv(envname = envname) -``` +## Running Walking with Different Python Environments -and then run examples such as: +If you want to use both walking estimation from `forest` and +`stepcount`, you can run them in separate R processes using `callr` to +avoid Python package conflicts. Here’s how you can do it: ``` r -library(walking) +library(callr) library(stepcount) -envname = "stepcount2" - -# if you have RETICULATE_PYTHON set -stepcount::unset_reticulate_python() -stepcount::use_stepcount_condaenv(envname = envname) - +#> Warning in reticulate::py_require("stepcount>=3.11.0", python_version = "3.10"): Python version requirements cannot be changed after Python has been initialized. +#> * Python version request: '3.10' (from package:stepcount) +#> * Python version initialized: '3.11.15' csv_file = system.file("test_data_bout.csv", package = "walking") -x = readr::read_csv(csv_file) -colnames(x)[colnames(x) == "UTC time"] = "time" -res = find_walking(data = x) +data = readr::read_csv(csv_file) +#> Rows: 98 Columns: 6 +#> ── Column specification ──────────────────────────────────────────────────────── +#> Delimiter: "," +#> chr (1): accuracy +#> dbl (4): timestamp, x, y, z +#> dttm (1): UTC time +#> +#> ℹ Use `spec()` to retrieve the full column specification for this data. +#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message. +colnames(data)[colnames(data) == "UTC time"] = "time" + +stepcount_callr = function(data, + ...) { + + reticulate::py_require("stepcount==3.11.0", python_version = "3.10") + sc <- reticulate::import("stepcount") + stepcount::stepcount_check() + + res = stepcount::stepcount(data, ...) + return(res) +} + +# 2. Run the isolated background R process +result <- callr::r( + func = stepcount_callr, + show = TRUE, + args = list(data = data) # Safely injects data into the process +) +#> Loading model... +#> Downloading https://wearables-files.ndph.ox.ac.uk/files/models/stepcount/ssl-20230208.joblib.lzma... +#> Checking Data +#> Writing file to CSV... +#> Reading in Data for Stepcount +#> /Users/johnmuschelli/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/12AzDesQwp07_KC6/lib/python3.10/site-packages/actipy/processing.py:387: UserWarning: Skipping calibration: Insufficient stationary samples: 0 < 50 +#> warnings.warn(f"Skipping calibration: Insufficient stationary samples: {len(xyz)} < {calib_min_samples}") +#> Predicting from Model +#> Running step counter... +#> Gravity calibration...Gravity calibration... Done! (0.01s) +#> Nonwear detection...Nonwear detection... Done! (0.01s) +#> Resampling...Resampling... Done! (0.03s) +#> Defining windows... +#> 0%| | 0/1 [00:00 /Users/johnmuschelli/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/12AzDesQwp07_KC6/lib/python3.10/site-packages/stepcount/models.py:467: UserWarning: No data to predict +#> warnings.warn("No data to predict") +#> Processing Result +#> Using local /Users/johnmuschelli/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/12AzDesQwp07_KC6/lib/python3.10/site-packages/stepcount/torch_hub_cache/OxWearables_ssl-wearables_v1.0.0 +#> /usr/local/Cellar/python@3.10/3.10.20_1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown +#> warnings.warn('resource_tracker: There appear to be %d ' +head(result) +#> $steps +#> # A tibble: 1 × 2 +#> time steps +#> +#> 1 2020-02-25 18:18:31 NaN +#> +#> $walking +#> # A tibble: 1 × 2 +#> time walking +#> +#> 1 2020-02-25 18:18:31 NaN +#> +#> $step_times +#> [1] time +#> <0 rows> (or 0-length row.names) +#> +#> $info +#> $info$CalibNumSamples +#> [1] 0 +#> +#> $info$`CalibErrorBefore(mg)` +#> [1] NaN +#> +#> $info$`CalibErrorAfter(mg)` +#> [1] NaN +#> +#> $info$CalibOK +#> [1] 0 +#> +#> $info$`NonwearTime(days)` +#> [1] 0 +#> +#> $info$NumNonwearEpisodes +#> [1] 0 +#> +#> $info$`WearTime(days)` +#> [1] 0.0001126389 +#> +#> $info$NumInterrupts +#> [1] 0 +#> +#> $info$Covers24hOK +#> [1] 0 +#> +#> $info$ResampleRate +#> [1] 30 +#> +#> $info$NumTicksAfterResample +#> [1] 293 +#> +#> $info$Filename +#> [1] "/private/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T/Rtmpteefb1/file4e0f3962f3e5.csv" +#> +#> $info$Device +#> [1] ".csv" +#> +#> $info$`Filesize(MB)` +#> [1] 0 +#> +#> $info$SampleRate +#> [1] 10 +#> +#> $info$StartTime +#> [1] "2020-02-25 18:18:31" +#> +#> $info$EndTime +#> [1] "2020-02-25 18:18:40" + +forest_callr = function(data, + ...) { + reticulate::py_require( + "git+https://github.com/onnela-lab/forest@45fb41038bd46c25d9e6a4442aa74fa03b501317", + python_version = "3.11") + fr = reticulate::import("forest") + oak = fr$oak$base + oak + res = walking::estimate_steps_forest(data, ...) + return(res) +} + +# 2. Run the isolated background R process +fresult <- callr::r( + func = forest_callr, + show = TRUE, + args = list(data = data) # Safely injects data into the process +) +#> Preprocessing Bout +#> Bout is Preprocessed +#> OAK: Find walking is done +head(fresult) +#> time steps +#> 1 2020-02-25 18:18:31 1.65 +#> 2 2020-02-25 18:18:32 1.60 +#> 3 2020-02-25 18:18:33 1.55 +#> 4 2020-02-25 18:18:34 1.60 +#> 5 2020-02-25 18:18:35 1.55 +#> 6 2020-02-25 18:18:36 1.85 ``` - -Remember, however, best practices for Python is “Always create a -separate virtual environment for each project” and sometimes one for -each “goal”. diff --git a/README_cache/gfm/__packages b/README_cache/gfm/__packages new file mode 100644 index 0000000..715714e --- /dev/null +++ b/README_cache/gfm/__packages @@ -0,0 +1,11 @@ +base +methods +colorout +datasets +utils +grDevices +graphics +stats +walking +callr +stepcount diff --git a/README_cache/gfm/unnamed-chunk-2_dbaf97c3887afa912b9be6b97e070cab.RData b/README_cache/gfm/unnamed-chunk-2_dbaf97c3887afa912b9be6b97e070cab.RData new file mode 100644 index 0000000000000000000000000000000000000000..4d300e956869e47ea4227450c26e91c39049ed31 GIT binary patch literal 4842 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 Wyd$dOL^+H+G($gsbk<*e0RRAhy=0*P literal 0 HcmV?d00001 From 4b00aa89a749e92f79f84cdb0ba122f94bf8e481 Mon Sep 17 00:00:00 2001 From: muschellij2 Date: Tue, 2 Jun 2026 12:17:46 -0400 Subject: [PATCH 2/5] fixing buildignore --- .Rbuildignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.Rbuildignore b/.Rbuildignore index 8cd0d09..0c7d466 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -10,3 +10,6 @@ ^\.positai$ ^\.claude$ ^todo\.txt$ +^README_cache$ +^\.DS_Store$ +^*/\.DS_Store$ From 415458dd5b62a679178803f30eb47c5bffdac966 Mon Sep 17 00:00:00 2001 From: muschellij2 Date: Tue, 2 Jun 2026 12:19:05 -0400 Subject: [PATCH 3/5] fixing buildignore --- .Rbuildignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.Rbuildignore b/.Rbuildignore index 0c7d466..2722dda 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -12,4 +12,3 @@ ^todo\.txt$ ^README_cache$ ^\.DS_Store$ -^*/\.DS_Store$ From 12da20bfdd8796af05bb447f73dba038e4f71696 Mon Sep 17 00:00:00 2001 From: muschellij2 Date: Thu, 4 Jun 2026 13:33:05 -0400 Subject: [PATCH 4/5] trying to reduce object sizes --- DESCRIPTION | 2 +- R/find_walking.R | 9 +++++---- R/preprocess_bout.R | 6 ++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index aa8943c..83c1685 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: walking Title: Segments Accelerometry Data into Walking using the Python `forest` Module -Version: 0.5.1 +Version: 0.6.0 Authors@R: person(given = "John", family = "Muschelli", diff --git a/R/find_walking.R b/R/find_walking.R index a8d3fc3..54040ce 100644 --- a/R/find_walking.R +++ b/R/find_walking.R @@ -69,7 +69,9 @@ find_walking = function( if (verbose) { message("Bout is Preprocessed") } - vm_bout = pp_out$vm_bout$vm + vm_bout = pp_out$vm_bout + vm = vm_bout$vm + vm_bout$vm = NULL # step_frequency = do.call(reticulate::tuple, as.list(step_frequency)) oak = oak_base() @@ -80,7 +82,7 @@ find_walking = function( # fs = sample_rate) cadence_bout = oak$find_walking( - vm_bout = vm_bout, + vm_bout = vm, fs = sample_rate_analysis, min_amp = min_amplitude, step_freq = step_frequency, @@ -91,9 +93,8 @@ find_walking = function( if (verbose) { message("OAK: Find walking is done") } - vm_bout = pp_out$vm_bout + vm_bout$steps = cadence_bout - vm_bout$vm = NULL vm_bout = as.data.frame(vm_bout) # need to remove 1D aspect vm_bout$time = c(vm_bout$time) diff --git a/R/preprocess_bout.R b/R/preprocess_bout.R index 005f8ea..bf00bdf 100644 --- a/R/preprocess_bout.R +++ b/R/preprocess_bout.R @@ -180,11 +180,17 @@ preprocess_bout_r = function(data, sample_rate = 10L) { vm_bout_interp = np$sqrt(x_bout_interp**2 + y_bout_interp**2 + z_bout_interp**2) - 1 + rm(x_bout_interp) + rm(y_bout_interp) + rm(z_bout_interp) vm_bout = list( t_bout_interp, vm_bout_interp ) + rm(vm_bout_interp) + rm(t_bout_interp) + process_vm_bout(vm_bout, tz = orig_tz, sample_rate = sample_rate) } From 6587a7fc3ebf29ee0d5abb4bf5e54bb1c6e1a20b Mon Sep 17 00:00:00 2001 From: muschellij2 Date: Thu, 4 Jun 2026 13:37:05 -0400 Subject: [PATCH 5/5] added new tests --- tests/testthat/test-api.R | 64 +++++++++++++++++++++++++++++++++ tests/testthat/test-internals.R | 31 ++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/testthat/test-api.R create mode 100644 tests/testthat/test-internals.R diff --git a/tests/testthat/test-api.R b/tests/testthat/test-api.R new file mode 100644 index 0000000..3d47fee --- /dev/null +++ b/tests/testthat/test-api.R @@ -0,0 +1,64 @@ +testthat::test_that("estimate_steps_verisense validates inputs and dispatches methods", { + testthat::expect_error( + estimate_steps_verisense(1:10, sample_rate = 10L), + "needs a data set/data.frame" + ) + + csv_file = system.file("test_data_bout.csv", package = "walking") + data = utils::read.csv(csv_file, stringsAsFactors = FALSE, check.names = FALSE) + data$time = as.POSIXct(data$`UTC time`, tz = "UTC") + data$`UTC time` = NULL + + original = estimate_steps_verisense(data, sample_rate = 10L, method = "original") + revised = estimate_steps_verisense(data, sample_rate = 10L, method = "revised") + + testthat::expect_s3_class(original, "data.frame") + testthat::expect_s3_class(revised, "data.frame") + testthat::expect_named(original, c("time", "steps")) + testthat::expect_named(revised, c("time", "steps")) + testthat::expect_true(nrow(original) > 0L) + testthat::expect_true(nrow(revised) > 0L) + + resample_data = data.frame( + time = as.POSIXct("2020-01-01 00:00:00", tz = "UTC") + c(0, 1, 2), + X = c(0.1, 0.2, 0.3), + Y = c(0.2, 0.1, 0.2), + Z = c(1, 1, 1) + ) + testthat::expect_warning( + estimate_steps_verisense( + resample_data, + sample_rate = 10L, + resample_to_15hz = TRUE, + method = "original" + ), + "sample_rate will be ignored because resample_to_15hz is TRUE" + ) +}) + + +testthat::test_that("estimate_steps_sdt matches sdt_count_steps", { + times = as.POSIXct("2020-01-01 00:00:00", tz = "UTC") + seq(0, by = 0.01, length.out = 100) + data = data.frame( + time = times, + X = 0, + Y = 0, + Z = 0 + ) + + wrist = sdt_count_steps(data, sample_rate = 100L, location = "wrist", verbose = FALSE) + waist = sdt_count_steps(data, sample_rate = 100L, location = "waist", verbose = FALSE) + wrapper = estimate_steps_sdt(data, sample_rate = 100L, location = "wrist", verbose = FALSE) + + testthat::expect_equal(wrist, wrapper) + testthat::expect_equal(waist$steps, 0) + testthat::expect_equal(wrist$steps, 0) + testthat::expect_equal(wrist$time, as.POSIXct("2020-01-01 00:00:00", tz = "UTC")) +}) + + +testthat::test_that("have_forest returns a logical scalar", { + forest_available = suppressWarnings(have_forest()) + testthat::expect_type(forest_available, "logical") + testthat::expect_length(forest_available, 1L) +}) diff --git a/tests/testthat/test-internals.R b/tests/testthat/test-internals.R new file mode 100644 index 0000000..d282290 --- /dev/null +++ b/tests/testthat/test-internals.R @@ -0,0 +1,31 @@ +testthat::test_that("process_vm_bout converts and expands time correctly", { + times = as.numeric(as.POSIXct("2020-01-01 00:00:00", tz = "UTC")) + c(0.1234, 0.6234, 1.1234) + vm_bout = list(times, c(0.1, 0.2, 0.3)) + + out = process_vm_bout(vm_bout, tz = "UTC", sample_rate = 2L) + + testthat::expect_named(out, c("vm_bout", "vm_data")) + testthat::expect_s3_class(out$vm_bout$time, "POSIXct") + testthat::expect_equal( + as.numeric(out$vm_bout$time), + times, + tolerance = 0.01 + ) + testthat::expect_equal(out$vm_data$time[1], as.POSIXct("2020-01-01 00:00:00", tz = "UTC")) + testthat::expect_equal(as.numeric(diff(out$vm_data$time)), c(0.5, 0.5)) +}) + + +testthat::test_that("create_peak_info and rowWhichMaxIndex return expected values", { + peak_info = create_peak_info(3L) + testthat::expect_named( + peak_info, + c("peak_location", "acc_magnitude", "periodicity", "similarity", "continuity") + ) + testthat::expect_true(all(is.na(peak_info))) + + index_mat = matrix(c(1, 2, 3, 4, 5, 6), nrow = 2, byrow = TRUE) + value_mat = matrix(c(1, 4, 2, 7, 6, 5), nrow = 2, byrow = TRUE) + + testthat::expect_equal(rowWhichMaxIndex(index_mat, value_mat), c(2, 4)) +})