Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
cb5b56a
Hi Andrew/Harvey, just testing whether I can get rid of the @import i…
DavidRach Dec 1, 2025
09d2ba1
With ggplot2 switching to v4, and ggcyto shifts, flowGate is failing …
DavidRach Feb 21, 2026
db5d8c8
as.ggplot clashing with residual ggcyto_GatingSet class, on stripping…
DavidRach Feb 21, 2026
2fb4897
Worked through Shiny capture options, gate is being created, but retu…
DavidRach Feb 21, 2026
890bb64
Fixed! The two major changes are the linguering GatingSet class that …
DavidRach Feb 21, 2026
34aa109
Unit test for all four interactive plot types. Need to check ggplot2 …
DavidRach Feb 21, 2026
d84ac97
Missing description file comma
DavidRach Apr 4, 2026
37b6ce1
Rollback requirement to R >= 4.4 for Cytometry in R class
DavidRach Apr 16, 2026
d56d7d3
Initial work on gs_gate_interactive_adjust, which will iterate throug…
DavidRach Jun 20, 2026
1d5f81d
Modified gs_gate_interactive_adjust to show existing gate, and if don…
DavidRach Jun 20, 2026
d1c628d
Added a GatingSet to openCyto template function, everything being wri…
DavidRach Jun 20, 2026
36d8576
SpanGate adjustments and openCyto template exports are operational
DavidRach Jun 21, 2026
082aff7
Incorporation of additional metadata columns to pData was causing gat…
DavidRach Jun 27, 2026
ec1f1b9
AdjustAll argument for applyGateCloseSwap to adjust all specimens wit…
DavidRach Jun 27, 2026
2c582bc
Quality of life change for the Shiny, when only one-dimension provide…
DavidRach Jun 28, 2026
5cca8dd
Brough over Bioconductor flowGate version 1.13.1 differences to bring…
DavidRach Jul 2, 2026
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: 12 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
Package: flowGate
Type: Package
Title: Interactive Cytometry Gating in R
Version: 0.99.2
Version: 1.13.1
Authors@R: c(person("Andrew",
"Wight",
email = "andrew.wight10@gmail.com",
role = c("aut", "cre")),
role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-3116-8722")),
person("Harvey",
"Cantor",
email = "Harvey_Cantor@dfci.harvard.edu",
role = c("aut", "ldr")))
role = c("aut", "ldr"),
comment = c(ORCID = "0000-0002-3313-2478")))
Description: flowGate adds an interactive Shiny app to allow manual
GUI-based gating of flow cytometry data in R. Using flowGate,
you can draw 1D and 2D span/rectangle gates, quadrant gates,
Expand All @@ -19,6 +21,8 @@ Description: flowGate adds an interactive Shiny app to allow manual
cytometerists looking to take advantage of R for cytometry
analysis, without necessarily having a lot of R experience.
License: MIT + file LICENSE
URL: https://www.bioconductor.org/packages/release/bioc/html/flowGate.html
BugReports: https://github.com/NKInstinct/flowGate/issues
Encoding: UTF-8
LazyData: false
Imports:
Expand All @@ -34,14 +38,15 @@ Imports:
Depends:
flowWorkspace (>= 4.0.6),
ggcyto (>= 1.16.0),
R (>= 4.2)
RoxygenNote: 7.2.3
R (>= 4.4)
RoxygenNote: 7.3.3
Suggests:
knitr,
rmarkdown,
stringr,
tidyverse,
testthat
testthat,
vdiffr
VignetteBuilder: knitr
biocViews:
Software,
Expand All @@ -50,3 +55,4 @@ biocViews:
Preprocessing,
ImmunoOncology,
DataImport

58 changes: 55 additions & 3 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
# Generated by roxygen2: do not edit by hand

export(gs_apply_gate_check)
export(gs_apply_gating_strategy)
export(gs_gate_interactive)
export(gs_gate_interactive_adjust)
export(gs_gate_transform_interactive)
import(BiocManager)
import(flowWorkspace)
import(ggcyto)
export(gs_to_openCyto)
importFrom(BiocManager,install)
importFrom(dplyr,bind_rows)
importFrom(flowCore,polygonGate)
importFrom(flowCore,quadGate)
importFrom(flowCore,rectangleGate)
importFrom(flowCore,transform_gate)
importFrom(flowWorkspace,GatingSet)
importFrom(flowWorkspace,flowjo_biexp)
importFrom(flowWorkspace,gh_pop_get_gate)
importFrom(flowWorkspace,gs_get_pop_paths)
importFrom(flowWorkspace,gs_pop_add)
importFrom(flowWorkspace,gs_pop_get_gate)
importFrom(flowWorkspace,gs_pop_get_parent)
importFrom(flowWorkspace,gs_pop_remove)
importFrom(flowWorkspace,recompute)
importFrom(ggcyto,as.ggplot)
importFrom(ggcyto,geom_gate)
importFrom(ggcyto,ggcyto)
importFrom(ggcyto,scale_x_flowjo_biexp)
importFrom(ggcyto,scale_y_flowjo_biexp)
importFrom(ggplot2,aes)
importFrom(ggplot2,aes_)
importFrom(ggplot2,coord_cartesian)
importFrom(ggplot2,element_blank)
importFrom(ggplot2,element_text)
importFrom(ggplot2,geom_density)
importFrom(ggplot2,geom_hex)
importFrom(ggplot2,geom_hline)
importFrom(ggplot2,geom_path)
importFrom(ggplot2,geom_vline)
importFrom(ggplot2,scale_x_continuous)
importFrom(ggplot2,scale_y_continuous)
importFrom(ggplot2,theme)
importFrom(ggplot2,theme_gray)
importFrom(methods,is)
importFrom(openCyto,register_plugins)
importFrom(purrr,map)
importFrom(purrr,pluck)
importFrom(purrr,pmap)
importFrom(rlang,"!!")
importFrom(rlang,.data)
importFrom(shiny,actionButton)
importFrom(shiny,brushOpts)
importFrom(shiny,checkboxInput)
importFrom(shiny,fluidPage)
importFrom(shiny,mainPanel)
importFrom(shiny,numericInput)
importFrom(shiny,observeEvent)
importFrom(shiny,plotOutput)
importFrom(shiny,radioButtons)
importFrom(shiny,reactive)
importFrom(shiny,reactiveValues)
importFrom(shiny,renderPlot)
importFrom(shiny,renderText)
importFrom(shiny,runApp)
importFrom(shiny,shinyApp)
importFrom(shiny,sidebarLayout)
importFrom(shiny,sidebarPanel)
importFrom(shiny,sliderInput)
importFrom(shiny,stopApp)
importFrom(shiny,tabPanel)
importFrom(shiny,tabsetPanel)
importFrom(shiny,textOutput)
importFrom(shiny,titlePanel)
importFrom(shiny,updateTabsetPanel)
importFrom(stringr,str_equal)
importFrom(tibble,tribble)
importFrom(utils,write.csv)
11 changes: 9 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# Changes in version 0.99.2 (2023-03-15)
- Package cleanup after initial Bioconductor submission
# Changes in version 0.99.3 (2023-03-15)
- Document cleanup as part of bioconductor review

# Changes in version 1.13.1 (2026-07-02)
- Implemented fixes due to the ggplot2 version 4 changes, with
the update ggcyto syntax changes
- Where appropiate, switched from import to importFrom tags
- Implemented gs_apply_gate_check to allow adjustment existing gates
- Additional unit tests to test suite
19 changes: 14 additions & 5 deletions R/applyGateClose.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#' @param gateType The selected type of gate (from UI).
#' @param filterId The gate name specified by the user.
#' @param gg The plot object from vars$plot.
#'
#' @importFrom flowCore polygonGate rectangleGate quadGate
#' @importFrom flowWorkspace gs_pop_add recompute
#'
#' @return The original GatingSet with the newly drawn gate applied.
#'
Expand All @@ -12,21 +15,27 @@
applyGateClose <- function(
gs, subset, coords, gateType, filterId, gg, useBiex, bins, xMax, xWidth,
xPos, xNeg, yMax, yWidth, yPos, yNeg){

TheNames <- names(gg$data)
LastTwo <- tail(TheNames, 2)
FinalOne <- tail(TheNames, 1)

if(gateType == "polygonGate"){
names(coords) <- c(names(gg[[1]])[[3]], names(gg[[1]])[[4]])
names(coords) <- LastTwo
coords <- as.matrix(coords)
gate <- flowCore::polygonGate(coords, filterId = filterId)
} else if(gateType == "spanGate"){
names(coords) <- c(names(gg[[1]])[[3]])
names(coords) <- FinalOne
gate <- flowCore::rectangleGate(coords, filterId = filterId)
} else if(gateType == "quadGate"){
names(coords) <- c(names(gg[[1]])[[3]], names(gg[[1]])[[4]])
names(coords) <- LastTwo
gate <- flowCore::quadGate(coords, filterId = filterId)
} else if(gateType == "rectangleGate"){
names(coords) <- c(names(gg[[1]])[[3]], names(gg[[1]])[[4]])
names(coords) <- LastTwo
gate <- flowCore::rectangleGate(coords, filterId = filterId)
}
gs_pop_add(gs, gate, parent = subset)

gs_pop_add(gs=gs, gate=gate, parent = subset)
recompute(gs)

if(useBiex){
Expand Down
63 changes: 63 additions & 0 deletions R/applyGateCloseSwap.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#' Apply gate from gs_gate_interactive
#'
#' @param coords The coordinates of the interactively drawn gate.
#' @param gateType The selected type of gate (from UI).
#' @param filterId The gate name specified by the user.
#' @param gg The plot object from vars$plot.
#' @param AdjustAll Default FALSE, applies the gate correction to the entire gating set.
#'
#' @importFrom flowCore polygonGate rectangleGate quadGate
#' @importFrom flowWorkspace gs_pop_add recompute
#'
#' @return The original GatingSet with the newly drawn gate applied.
#'
#' @noRd
#'
applyGateCloseSwap <- function(
gs, subset, coords, gateType, filterId, gg, useBiex, bins, xMax, xWidth,
xPos, xNeg, yMax, yWidth, yPos, yNeg, sample, AdjustAll=FALSE){

TheNames <- names(gg$data)
LastTwo <- tail(TheNames, 2)
FinalOne <- tail(TheNames, 1)

if(gateType == "polygonGate"){
names(coords) <- LastTwo
coords <- as.matrix(coords)
gate <- flowCore::polygonGate(coords, filterId = filterId)
} else if(gateType == "spanGate"){
names(coords) <- FinalOne
gate <- flowCore::rectangleGate(coords, filterId = filterId)
} else if(gateType == "quadGate"){
names(coords) <- LastTwo
gate <- flowCore::quadGate(coords, filterId = filterId)
} else if(gateType == "rectangleGate"){
names(coords) <- LastTwo
gate <- flowCore::rectangleGate(coords, filterId = filterId)
}

# gs_pop_add(gs, gate, parent = subset)
TheList <- list(gate)

if (AdjustAll==FALSE){
names(TheList) <- sampleNames(gs[sample])
gs_pop_set_gate(gs[sample], filterId, TheList)
recompute(gs[sample])
} else {
TheList <- rep(TheList, length(sampleNames(gs)))
names(TheList) <- sampleNames(gs)
gs_pop_set_gate(gs, filterId, TheList)
recompute(gs)
}

if(useBiex){
varsBiex <- list(X = list(
maxValue = xMax, widthBasis = xWidth, pos = xPos, neg = xNeg),
Y = list(
maxValue = yMax, widthBasis = yWidth, pos = yPos, neg = yNeg))
} else{
varsBiex <- "unused"
}
output <- list("Gate" = gate, "Bins" = bins, "Scaling" = varsBiex)
return(output)
}
9 changes: 9 additions & 0 deletions R/flowGate-package.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#' @description
#' To learn more about how to use flowGate, please start by browsing the vignettes:
#'
#' @keywords internal
"_PACKAGE"

## usethis namespace: start
## usethis namespace: end
NULL
24 changes: 24 additions & 0 deletions R/gateHandlers.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ coordBrush <- function(brush, gateType, useBiex, transX, transY){
return(res)
}

#' Internal for Unknown
#'
#' @param click TODOLIST
#' @param gateType TODOLIST
#' @param useBiex TODOLIST
#' @param transX TODOLIST
#' @param transY TODOLIST
#'
#' @noRd
#'
coordClick <- function(click, gateType, useBiex, transX, transY){
if(useBiex){
click$x <- transX(click$x)
Expand All @@ -44,6 +54,20 @@ coordClick <- function(click, gateType, useBiex, transX, transY){
return(res)
}

#' Internal for Unknown
#'
#' @param gateType TODOLIST
#' @param brush TODOLIST
#' @param click TODOLIST
#' @param biex TODOLIST
#' @param tX TODOLIST
#' @param tY TOODOLIST
#' @param append TODOLIST
#'
#' @importFrom dplyr bind_rows
#'
#' @noRd
#'
gateHandler <- function(gateType, brush, click, biex, tX, tY, append){
switch(gateType,
rectangleGate = ,
Expand Down
72 changes: 72 additions & 0 deletions R/gs_apply_gate_check.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#' The purpose of this function is to allow the readjustment of a gate on an
#' individual specimen via the Shiny app, quickly iterating through every
#' specimen present in the GatingSet.
#'
#' This allows for fine-tuning of the gate placement for non-representative
#' specimens, or when automated gating methods fail.
#'
#' @param gs A GatingSet or list of GatingSets.
#' @param gate A tibble-formatted gating strategy (see examples below)
#' @param sample Sample index in the GatingSet, default NULL will iterate through
#' all specimens in the GatingSet.
#' @param AdjustAll Default FALSE, applies the gate correction to the entire gating set.
#' @param ... Other parameters to pass to gs_gate_interactive(). Note that only
#' constant parameters should be supplied here---anything that varies should
#' be included in the gating_strategy tibble.
#'
#' @return the GatingSet or list of GatingSets with the gates in gating_strategy
#' applied as specified.
#'
#' @importFrom tibble tribble
#' @importFrom methods is
#' @importFrom purrr pmap
#'
#' @examples
#'
#' fs <- flowCore::read.flowSet(
#' path = system.file("extdata", package = "flowGate"), pattern = ".FCS$")
#'
#' gs <- flowWorkspace::GatingSet(fs)
#'
#' # Note - this is a very rudamentary GatingSet for example purposes only.
#' # Please see the vignette accompanying this package or the flowWorkspace
#' # documentation # for a complete look at creating a GatingSet.
#'
#' gating_strategy <- tibble::tribble(
#' ~filterId, ~dims, ~subset, ~coords,
#' "Lymphocytes", list("FSC-H", "SSC-H"), "root", list(c(0, 3e5), c(0, 3e5)),
#' "CD45 CD15", list("CD45 PE", "CD15 FITC"), "Lymphocytes", list(c(0, 3e5), c(0, 2e5)),
#' )
#'
#'
#' if(interactive()){
#' gs_apply_gating_strategy(gs,
#' gating_strategy = gating_strategy,
#' bins = 512) # note that extra args for gs_gate_interactive can be supplied.
#' }
#' @export
#'
gs_apply_gate_check <- function(gs, gate, sample=NULL, AdjustAll=FALSE, ...){
if(methods::is(gs, "GatingSet")){

if(is.null(sample)){
Samples <- seq_along(gs)
} else {Samples <- sample}

purrr::walk(
.x = Samples,
.f = function(sample) {
gs_gate_interactive_adjust(
gs = gs,
gate = gate,
sample = sample,
AdjustAll = AdjustAll,
...
)
}
)

} else {
stop("'gs' must be a GatingSet")
}
}
4 changes: 3 additions & 1 deletion R/gs_apply_gating_strategy.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#'
#' @importFrom tibble tribble
#' @importFrom methods is
#' @importFrom purrr pmap
#'
#' @examples
#'
Expand All @@ -52,10 +53,11 @@
#' bins = 512) # note that extra args for gs_gate_interactive can be supplied.
#' }
#' @export
#'
gs_apply_gating_strategy <- function(gs, gating_strategy, ...){
if(methods::is(gs, "GatingSet")){
purrr::pmap(gating_strategy,
flowGate::gs_gate_interactive, gs = gs, ...)
gs_gate_interactive, gs = gs, ...)
} else {
stop("'gs' must be a GatingSet")
}
Expand Down
Loading
Loading