The hosted Shiny app has moved from shinyapps.io to Posit Connect Cloud (git-backed deploy). The shinyapps.yaml GitHub Actions workflow is removed; Connect Cloud rebuilds inst/app from the repo and installs dependencies from the committed inst/app/manifest.json, regenerated by the new connect-manifest workflow.
radiatR 0.1.2
Breaking changes
The ctrax loader dialect and its optional R.matlab dependency have been removed. .mat files are no longer supported; read_tracks(dialect = "ctrax") now errors as an unknown dialect. Pre-computed orientation angles remain supported through the general ellipse_axis heading rule on any column.
read_tracks() now fails on non-finite coordinate rows by default, reporting the affected row numbers and ids; pass on_invalid = "drop" to drop them with a warning instead of the previous silent drop (breaking).
Bug fixes
The Shiny app no longer shows a previous analysis’s results after a new headings upload. In headings mode a failed file upload used to leave the earlier (e.g. example) headings in place, and the “example headings already loaded” shortcut could then display them as if they belonged to the file just selected. The upload now clears any prior analysis before reading and commits the parsed data only on success, and the shortcut to Results fires only for genuinely example-sourced headings.
c(Tracks, ...) now rejects trajectory ids that collide across the objects being combined, and errors when the inputs carry conflicting frame_rate, distance_scale, distance_unit, or normalize_xy metadata (including one input having it set and another not). Previously these were silently merged, discarding one object’s calibration in favour of the other’s, and could interleave rows from two different trajectories that happened to share an id. Per-id/per-run metadata (reference, trial_limits, sim_conditions, oob_points, oob_trials) is now merged/summed across all combined inputs instead of only the first object’s being kept.
read_tracks() and read_tracks_dir() now preserve trajectory identity when importing multiple files. Previously, reading a character vector of paths with no id column (the common case, relying on id_from_filename = TRUE) silently collapsed every file into a single "(multiple)" trajectory whose rows were then interleaved by time across files. Each file now yields its own trajectory keyed by the file-name stem. A new id_collision = c("error", "namespace") argument controls what happens when a real id value appears under more than one file: "error" (the default) stops with a message naming the colliding id and files, and "namespace" prefixes every id with its file stem (file::id). Multi-file imports with no id column and id_from_filename = FALSE now fail with a clear error instead of the silent collapse, and duplicate (id, time) keys produced by combining files are reported rather than passed through.
read_tracks(..., time_type = "frames", fps = ) no longer converts frame indices to seconds twice. The time column is now kept as a raw frame index and elapsed_seconds() (and everything built on it: track_duration(), track_speed(), velocity, and turning-rate) performs the frame -> seconds division exactly once, on demand, using the stored frame_rate(). Previously the loader divided by fps immediately and then stored the same fps as the frame rate, so downstream kinematics divided by fps a second time – e.g. an expected 60 units/s speed came out as 3600 units/s. Loading with time_type = "seconds" no longer stores a spurious frame rate either.
wrappedcauchy_fit()’s convergence column now matches its documentation. circular::mle.wrappedcauchy() reports convergence as a logical, which the previous code passed through as.integer(), yielding 1 for a converged fit – the opposite of the documented “0 = converged”. The column is now 0 when the fit converged and 1 when it did not, and the (incorrect) “optim return code” wording in the docs has been corrected.
Between-group tests (test_mean_directions(), test_concentration(), test_distributions()) now signal a structured radiatR_nonestimable condition (carrying method, group, n, and reason) for non-estimable inputs, so callers can distinguish expected non-estimable cases from bugs.
App
The app no longer assumes a capture rate of 30 fps. The frame-rate controls now start unset, and time/speed colouring, the kinematics plot and its downloads, and the generated kinematics code stay disabled until a positive finite frame rate is entered or carried by the loaded data. The app shows whether the active rate came from the data or was entered by the user, and downloaded kinematics code no longer emits a fabricated set_frame_rate(ts, 30) when no rate is set. Previously, uncalibrated numeric-frame data produced plausible-looking speed and turning-rate results based on the unsupported default.
Ingest failures now show the original exception (with affected rows/ids) under “Technical details” and no longer suppress ingest warnings; the group-comparison table shows the non-estimable reason instead of a blank dash and re-raises unexpected errors; downloads are gated (results_ok()) so a failed or partial run cannot emit an apparently-valid result.
radiatR 0.1.1
New features
New test_gof() tests whether a sample of headings fits a wrapped Cauchy distribution (Watson’s U^2 on the probability-integral transform, with a parametric-bootstrap p-value), closing the wrapped-Cauchy half of the non-von-Mises goodness-of-fit gap. Jones-Pewsey GOF remains deferred.
test_uniformity() gains test = "pycke", the Pycke (2010) omnibus uniformity test — like Hermans-Rasson, powerful against multimodal and asymmetric departures from uniformity, with a Monte-Carlo p-value.
Bug fixes
radiate() no longer labels every trajectory by its id when a plot has many tracks. The automatic fallback to the id/group column now applies only when that column has at most 12 distinct values, so many-track plots (e.g. the 235-trial cpunctatus) render cleanly instead of being buried under overlapping trial-id labels. Pass label_col explicitly to force labelling regardless of track count.
radiate(clip_tracks = TRUE) (the default) now also clips beyond-circumference overshoot in the absolute frame (coords = "absolute"), not just the relative frame. The relative frame is a rotation of the absolute one, so rho is identical in both; the previous relative-only restriction let coords = "absolute" plots (e.g. in the package vignette) draw tracks visibly outside the unit circle.
get_all_object_pos() now reports out-of-bounds track points (radius > 1) with a single aggregated message across the whole manifest, instead of one message per file.
App
Summary & stats now has a “Group comparison” card: test_mean_directions, test_concentration, and test_distributions run automatically across the selected Group-by column, showing whether groups differ in mean direction, concentration, or overall distribution (not just whether each is individually non-uniform).
The app now exposes an explicit Coordinates control for the per-trajectory shape transform (normalize_xy), which was previously pinned on with no way to opt out. The transform fits each trajectory to the unit circle independently and preserves path shape, not bearings from a fixed arena origin; the control labels it as such rather than as a calibration. Downloaded figure, statistics, and kinematics scripts now emit the normalize_xy value the app actually loaded with, instead of silently falling back to the package default.
radiatR 0.1.0
First public release.
Read and construct movement Tracks, with support for absolute and relative coordinate frames and frame-rate / time metadata.
Plot circular data with radiate(), including axial overlays, faceting, grouping, perimeter labelling and circular boxplots.
Compute kinematics: speed, path sinuosity, per-row velocity angle and related trajectory summaries.
Circular statistics: circular and concentration regression, model selection, and tests of mean direction, symmetry and unimodality.