Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,6 @@ jobs:
steps:
- uses: actions/checkout@v7

- uses: actions/setup-python@v7
with:
python-version: '3.x'

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install scipy numpy

- name: Set RETICULATE_PYTHON (Unix)
if: runner.os != 'Windows'
run: echo "RETICULATE_PYTHON=$(which python)" >> $GITHUB_ENV

- name: Set RETICULATE_PYTHON (Windows)
if: runner.os == 'Windows'
run: echo "RETICULATE_PYTHON=$((Get-Command python).Source)" >> $env:GITHUB_ENV
shell: pwsh

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
Expand Down
11 changes: 0 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ jobs:
steps:
- uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: "3.12"

- name: Install Python dependencies and set RETICULATE_PYTHON
run: |
python -m pip install --upgrade pip
pip install scipy numpy
echo "RETICULATE_PYTHON=$(which python)" >> $GITHUB_ENV

- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
Expand Down
7 changes: 0 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Thank you for your interest in contributing to `ClassiPyR`! This document provid

- R (>= 4.0.0)
- devtools package for development
- Python with `scipy` (required for saving .mat annotation files)

### Setting Up the Development Environment

Expand All @@ -26,12 +25,6 @@ Thank you for your interest in contributing to `ClassiPyR`! This document provid
devtools::load_all()
```

4. Set up Python environment (required for saving .mat annotation files):
```r
library(iRfcb)
ifcb_py_install(envname = "./venv")
```

### Running the App During Development

```r
Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ Imports:
shinyFiles,
bslib,
curl,
iRfcb (>= 0.8.1),
iRfcb (>= 0.10.0),
lifecycle,
dplyr,
DT,
jsonlite,
reticulate,
DBI,
RSQLite
Suggests:
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ importFrom(iRfcb,ifcb_get_mat_variable)
importFrom(iRfcb,ifcb_zip_matlab)
importFrom(iRfcb,ifcb_zip_pngs)
importFrom(jsonlite,fromJSON)
importFrom(reticulate,py_available)
importFrom(lifecycle,deprecated)
importFrom(shiny,shinyApp)
importFrom(shinyFiles,shinyDirButton)
importFrom(shinyjs,useShinyjs)
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# ClassiPyR (development version)

- ClassiPyR now requires R >= 4.4.0 (for base R's `%||%` operator, which the app already relied on).
- **Python is no longer required.** iRfcb 0.10.0 reads and writes MATLAB `.mat` files with a native R implementation, so ClassiPyR now requires `iRfcb >= 0.10.0` and all Python-related code has been removed: `reticulate` is no longer an Import, the app no longer initializes a Python environment at startup, and the "Python not available" warnings and export blocks are gone — `.mat` saving, SQLite → `.mat` export and MATLAB ZIP export work out of the box for everyone.
- `init_python_env()` is deprecated and now a no-op; the `venv_path` argument of `run_app()` is deprecated and ignored (a warning is issued when supplied). The `python_venv_path` entry in saved settings is ignored.
- If you need a Python environment for other iRfcb features (e.g. feature extraction), use `iRfcb::ifcb_py_install()` directly.

## New features

Expand Down
4 changes: 1 addition & 3 deletions R/database.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# Provides functions to store and retrieve annotations in a local SQLite
# database as an alternative to .mat files. SQLite is the default storage
# backend - it works out of the box with no Python dependency.
# backend.

#' @importFrom DBI dbConnect dbDisconnect dbWriteTable dbGetQuery dbExecute
#' @importFrom RSQLite SQLite
Expand Down Expand Up @@ -656,7 +656,6 @@ import_mat_to_db <- function(mat_path, db_path, sample_name,
#'
#' Reads annotations for a single sample from the database and writes a
#' MATLAB-compatible annotation file using \code{iRfcb::ifcb_create_manual_file}.
#' Requires Python with scipy.
#'
#' @param db_path Path to the SQLite database file
#' @param sample_name Sample name
Expand Down Expand Up @@ -781,7 +780,6 @@ import_all_mat_to_db <- function(mat_folder, db_path,
#' Bulk export all annotated samples from SQLite to .mat files
#'
#' Exports every sample in the database to a MATLAB-compatible annotation file.
#' Requires Python with scipy.
#'
#' @param db_path Path to the SQLite database file
#' @param output_folder Folder where .mat files will be written
Expand Down
29 changes: 15 additions & 14 deletions R/run_app.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
#' Run the ClassiPyR Shiny Application
#'
#' Launches the ClassiPyR Shiny app for manual image classification and validation of IFCB data.
#' This app relies on the iRfcb package for reading IFCB data files and requires
#' Python (via reticulate) for saving MATLAB .mat files.
#' This app relies on the iRfcb package for reading and writing IFCB data files,
#' including MATLAB .mat files, entirely in R.
#'
#' @param venv_path Optional path to a Python virtual environment. When specified,
#' this path takes priority over any saved venv path in settings, both for Python
#' initialization at startup and in the Settings UI. If NULL (default), the app
#' uses any saved venv path from settings, or falls back to a 'venv' folder in
#' the current working directory.
#' @param venv_path `r lifecycle::badge("deprecated")` Ignored. ClassiPyR no
#' longer requires Python; .mat files are read and written natively in R
#' (iRfcb >= 0.10.0).
#' @param reset_settings If TRUE, deletes saved settings before starting the app.
#' Useful for troubleshooting or starting fresh. Default is FALSE.
#' @param launch.browser If TRUE (default), opens the app in the system's default
Expand All @@ -24,9 +22,6 @@
#' # Run with default settings (opens in browser)
#' run_app()
#'
#' # Run with a specific Python virtual environment
#' run_app(venv_path = "/path/to/my/venv")
#'
#' # Run on a specific port
#' run_app(port = 3838)
#'
Expand All @@ -36,7 +31,8 @@
#' # Reset all settings and start fresh
#' run_app(reset_settings = TRUE)
#' }
run_app <- function(venv_path = NULL, reset_settings = FALSE, launch.browser = TRUE, ...) {
#' @md
run_app <- function(venv_path = deprecated(), reset_settings = FALSE, launch.browser = TRUE, ...) {
app_dir <- system.file("app", package = "ClassiPyR")
if (app_dir == "") {
stop("Could not find app directory. Try re-installing `ClassiPyR`.",
Expand All @@ -56,9 +52,14 @@ run_app <- function(venv_path = NULL, reset_settings = FALSE, launch.browser = T
# Capture user's working directory before Shiny changes it
options(ClassiPyR.startup_wd = getwd())

# Set venv path as option for the app to use
if (!is.null(venv_path)) {
options(ClassiPyR.venv_path = venv_path)
if (lifecycle::is_present(venv_path)) {
lifecycle::deprecate_warn(
"0.3.0", "run_app(venv_path)",
details = paste(
"The argument is ignored: ClassiPyR no longer requires Python",
"(iRfcb >= 0.10.0 reads and writes .mat files natively in R)."
)
)
}

shiny::runApp(app_dir, launch.browser = launch.browser, ...)
Expand Down
6 changes: 3 additions & 3 deletions R/sample_saving.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ NULL
#' Saves the current annotations for a sample. By default annotations are
#' stored in a local SQLite database (\code{annotations.sqlite} in the database
#' folder). Optionally, a MATLAB-compatible \code{.mat} file can also be
#' written (requires Python + scipy).
#' written.
#'
#' @param sample_name Sample name (e.g., "D20230101T120000_IFCB134")
#' @param classifications Current classifications data frame
Expand Down Expand Up @@ -105,7 +105,7 @@ save_sample_annotations <- function(sample_name,
output_folder = png_output_folder
)

# Save to SQLite (fast, no Python needed)
# Save to SQLite
if (save_format %in% c("sqlite", "both")) {
# Load class list if not provided
c2u <- class2use
Expand All @@ -116,7 +116,7 @@ save_sample_annotations <- function(sample_name,
save_annotations_db(db_path, sample_name, classifications, c2u, annotator)
}

# Save to .mat (requires Python + scipy)
# Save to .mat
if (save_format %in% c("mat", "both")) {
# Find ADC folder: use provided path, or fall back to get_sample_paths()
if (is.null(adc_folder)) {
Expand Down
115 changes: 22 additions & 93 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#' @importFrom bslib bs_theme
#' @importFrom DT renderDT
#' @importFrom jsonlite fromJSON
#' @importFrom reticulate py_available
#' @importFrom lifecycle deprecated
#' @importFrom dplyr filter
#' @importFrom DBI dbConnect dbDisconnect dbGetQuery dbWriteTable dbExecute
#' @importFrom RSQLite SQLite
Expand Down Expand Up @@ -796,99 +796,28 @@ create_empty_changes_log <- function() {

#' Initialize Python environment for iRfcb
#'
#' Checks if Python is already available via reticulate, otherwise tries to
#' use or create a virtual environment. Required for reading and writing
#' MATLAB .mat files.
#'
#' The resolution order is:
#' 1. If Python is already configured via reticulate, use it directly
#' (installs scipy if missing).
#' 2. If \code{venv_path} is provided and the virtual environment exists,
#' activate it.
#' 3. If \code{venv_path} is provided but does not exist, create it via
#' \code{\link[iRfcb]{ifcb_py_install}}.
#' 4. If \code{venv_path} is NULL, default to \code{./venv} in the current
#' working directory for steps 2--3.
#'
#' @param venv_path Optional path to virtual environment. If NULL (default),
#' uses a \code{venv} folder in the current working directory.
#' @return TRUE if Python is available, FALSE otherwise
#' @export
#' @examples
#' \dontrun{
#' # Initialize with default venv path (./venv)
#' success <- init_python_env()
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' # Initialize with custom venv path
#' success <- init_python_env("/path/to/my/venv")
#' `init_python_env()` was deprecated in ClassiPyR 0.3.0 and is now a no-op.
#' As of iRfcb 0.10.0, MATLAB .mat files are read and written with a native R
#' implementation, so ClassiPyR no longer requires Python.
#'
#' if (success) {
#' message("Python ready for MAT file operations")
#' }
#' }
#' If you need a Python environment for other iRfcb features (e.g. feature
#' extraction), set one up with [iRfcb::ifcb_py_install()].
#'
#' @param venv_path Ignored.
#' @return FALSE, invisibly
#' @export
#' @keywords internal
#' @md
init_python_env <- function(venv_path = NULL) {

tryCatch({
# Determine venv path: use provided path, or working directory default
if (is.null(venv_path) || venv_path == "") {
venv_path <- file.path(getwd(), "venv")
}

# Set RETICULATE_PYTHON *before* initialization so that py_discover_config()
# resolves to the correct environment. iRfcb's check_python_and_module()
# uses py_discover_config() + py_list_packages() which relies on this.
# Without this, py_discover_config() may return system Python even when
# reticulate is using a virtualenv, causing scipy checks to fail.
.set_reticulate_python <- function(venv) {
if (.Platform$OS.type == "windows") {
py <- file.path(venv, "Scripts", "python.exe")
} else {
py <- file.path(venv, "bin", "python")
}
if (file.exists(py)) {
Sys.setenv(RETICULATE_PYTHON = py)
return(TRUE)
}
FALSE
}

# Try the provided/configured venv first, then common reticulate defaults
venv_candidates <- unique(c(
venv_path,
path.expand("~/.virtualenvs/r-reticulate"),
path.expand("~/.virtualenvs/iRfcb")
))
for (candidate in venv_candidates) {
if (reticulate::virtualenv_exists(candidate) && .set_reticulate_python(candidate)) {
break
}
}

if (reticulate::py_available(initialize = TRUE)) {
# Check if scipy is installed (required for MAT file writing)
if (!reticulate::py_module_available("scipy")) {
message("Installing scipy...")
reticulate::py_install("scipy")
}
message("Python environment ready")
return(TRUE)
}

# Try to use existing venv
if (reticulate::virtualenv_exists(venv_path)) {
reticulate::use_virtualenv(venv_path, required = TRUE)
message("Using Python environment: ", venv_path)
return(TRUE)
}

# Create venv via iRfcb
message("Creating Python environment at: ", venv_path)
iRfcb::ifcb_py_install(venv_path)
reticulate::use_virtualenv(venv_path, required = TRUE)
return(TRUE)

}, error = function(e) {
warning("Failed to initialize Python environment: ", e$message)
return(FALSE)
})
lifecycle::deprecate_warn(
"0.3.0", "init_python_env()",
details = c(
"ClassiPyR no longer requires Python: iRfcb >= 0.10.0 reads and writes .mat files natively in R.",
"For other iRfcb features that use Python, see `iRfcb::ifcb_py_install()`."
)
)
invisible(FALSE)
}
23 changes: 3 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A Shiny application for manual (human) image classification and validation of Im

## Background

`ClassiPyR` was created to provide a lightweight, standalone annotation and validation tool that is fully compatible with the [ifcb-analysis](https://github.com/hsosik/ifcb-analysis) toolbox and custom classifiers (e.g. a CNN). The primary design goals were user-friendliness and portability—enabling researchers to work with IFCB data without complex setup requirements or dependencies on specific computing environments (other than Python and R). To achieve these goals efficiently, [Claude Code](https://code.claude.com/) was used for development.
`ClassiPyR` was created to provide a lightweight, standalone annotation and validation tool that is fully compatible with the [ifcb-analysis](https://github.com/hsosik/ifcb-analysis) toolbox and custom classifiers (e.g. a CNN). The primary design goals were user-friendliness and portability—enabling researchers to work with IFCB data without complex setup requirements or dependencies on specific computing environments (other than R). To achieve these goals efficiently, [Claude Code](https://code.claude.com/) was used for development.

## Features

Expand All @@ -21,7 +21,7 @@ A Shiny application for manual (human) image classification and validation of Im
- **Live Prediction**: One-click CNN classification via a remote Gradio API using [iRfcb](https://github.com/EuropeanIFCBGroup/iRfcb)
- **Multiple Formats**: Load from CSV, HDF5 or MATLAB classifier output
- **Flexible Image Source**: Load samples from ROI files or pre-extracted PNG sample folders
- **SQLite Storage**: Annotations stored in a local SQLite database by default - no Python needed
- **SQLite Storage**: Annotations stored in a local SQLite database by default
- **Efficient Workflow**: Drag-select, batch relabeling, class filtering
- **MATLAB Compatible**: Optional `.mat` export for [ifcb-analysis](https://github.com/hsosik/ifcb-analysis) toolbox
- **CNN Training Ready**: Organized PNG output by class
Expand Down Expand Up @@ -50,24 +50,7 @@ run_app()

See the [Getting Started](https://europeanifcbgroup.github.io/ClassiPyR/articles/getting-started.html) guide for detailed setup instructions.

### Python Setup (optional)

Python is **not required** for the default workflow. Annotations are stored in a local SQLite database that works out of the box.

Python is only needed if you want to export annotations as MATLAB `.mat` files for use with [ifcb-analysis](https://github.com/hsosik/ifcb-analysis). To set up using `iRfcb`:

```r
library(iRfcb)

# Define a path were the venv will be installed
venv_path <- "/path/to/your/venv"

# Install the venv
ifcb_py_install(venv_path)

# Launch with Python support
run_app(venv_path = venv_path)
```
No Python setup is needed: all file formats, including MATLAB `.mat` files for [ifcb-analysis](https://github.com/hsosik/ifcb-analysis), are read and written natively in R (via `iRfcb` >= 0.10.0).

## Documentation

Expand Down
Loading
Loading