From 52c5e66f2d1d5b88e03a33efb3ecb8e894109a7c Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Wed, 7 May 2025 09:37:05 +0200 Subject: [PATCH 01/28] README: add SO question hint --- README.Rmd | 8 ++++++++ README.md | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/README.Rmd b/README.Rmd index e0cedb7..24d923d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -67,6 +67,14 @@ And for a first impression of the package features type Visit the package documentation website: +## Questions + +If you get stuck, you can get help on [StackOverflow](https://stackoverflow.com/): + +- Make sure to read [How to write a good R question with a reproducible example](https://stackoverflow.com/collectives/r-language/articles/76995406/how-to-write-a-good-r-question-with-a-reproducible-example) before posting your question +- Add the tags `R` and `openrepgrid` to your question + + ## Contributing to OpenRepGrid You can contribute to OpenRepGrid in various ways. You can, for example, file a bug report, help improve the documentation or write code. See the our [contributing guide](https://docs.openrepgrid.org/CONTRIBUTING.html) for detailed information. diff --git a/README.md b/README.md index 5c694a8..9beffeb 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,16 @@ And for a first impression of the package features type Visit the package documentation website: +## Questions + +If you get stuck, you can get help on +[StackOverflow](https://stackoverflow.com/): + +- Make sure to read [How to write a good R question with a reproducible + example](https://stackoverflow.com/collectives/r-language/articles/76995406/how-to-write-a-good-r-question-with-a-reproducible-example) + before posting your question +- Add the tags `R` and `openrepgrid` to your question + ## Contributing to OpenRepGrid You can contribute to OpenRepGrid in various ways. You can, for example, From 9762f58c26fd9218506d89cee3a71393d0ecc03a Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 15:51:01 +0200 Subject: [PATCH 02/28] biplot2d: hide element and construct labels (fix #8) --- R/repgrid-plots.r | 30 +++++++++++++++++------------- man/biplotDraw.Rd | 4 ++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/R/repgrid-plots.r b/R/repgrid-plots.r index 70420b0..2dd45d0 100644 --- a/R/repgrid-plots.r +++ b/R/repgrid-plots.r @@ -832,8 +832,8 @@ prepareBiplotData <- function(x, dim = c(1, 2), map.dim = 3, biplotDraw <- function(x, inner.positioning = TRUE, outer.positioning = TRUE, - c.labels.inside = F, - flipaxes = c(F, F), + c.labels.inside = FALSE, + flipaxes = c(FALSE, FALSE), strokes.x = .1, strokes.y = .1, offsetting = TRUE, offset.labels = .0, offset.e = 1, axis.ext = .1, mai = c(.2, 1.5, .2, 1.5), @@ -1088,16 +1088,18 @@ biplotDraw <- function(x, # make construct lines if prompted if (c.lines) { - cli <- subset(x, type %in% c("cl", "cr") & showlabel == T) # select only labels that should be shown - segments(0, 0, cli$str.1.x, cli$str.1.y, col = col.c.lines) # lines form biplot center to outsides + cli <- subset(x, type %in% c("cl", "cr") & showlabel == TRUE) # select only labels that should be shown + if (nrow(cli) > 0) { + segments(0, 0, cli$str.1.x, cli$str.1.y, col = col.c.lines) # lines form biplot center to outsides + } } # make construct symbols - cs <- subset(x, type %in% c("cl", "cr") & showpoint == T & abs(x) < max.ext & abs(y) < max.ext) + cs <- subset(x, type %in% c("cl", "cr") & showpoint == TRUE & abs(x) < max.ext & abs(y) < max.ext) points(cs[c("x", "y")], col = cs$point.col, pch = 4, cex = cs$point.cex, xpd = xpd) # make element symbols - es <- subset(x, type == "e" & showpoint == T & abs(x) < max.ext & abs(y) < max.ext) + es <- subset(x, type == "e" & showpoint == TRUE & abs(x) < max.ext & abs(y) < max.ext) points(es[c("x", "y")], col = es$point.col, pch = 15, cex = es$point.cex, xpd = xpd) # positioning of element and constructs labels inside the plot @@ -1108,13 +1110,15 @@ biplotDraw <- function(x, x$showlabel[is.na(x$showlabel)] <- TRUE x$showpoint[is.na(x$showpoint)] <- TRUE - sh <- subset(x, showlabel == T & showpoint == T) # & - lpos <- pointLabel(sh[c("x", "y")], labels = sh$label, doPlot = FALSE, cex = cex.pos) # package maptools - x$x.pos <- NA - x$y.pos <- NA - sh$x.pos <- lpos$x - sh$y.pos <- lpos$y - x[x$showlabel == T & x$showpoint == T, ] <- sh + sh <- subset(x, showlabel == TRUE & showpoint == TRUE) + if (nrow(sh) > 0) { + lpos <- pointLabel(sh[c("x", "y")], labels = sh$label, doPlot = FALSE, cex = cex.pos) # package maptools + x$x.pos <- NA + x$y.pos <- NA + sh$x.pos <- lpos$x + sh$y.pos <- lpos$y + x[x$showlabel == TRUE & x$showpoint == TRUE, ] <- sh + } } else { # simple offsetting in y direction x$x.pos <- x$x x$y.pos <- NA diff --git a/man/biplotDraw.Rd b/man/biplotDraw.Rd index 756c0e9..cd3be96 100644 --- a/man/biplotDraw.Rd +++ b/man/biplotDraw.Rd @@ -8,8 +8,8 @@ biplotDraw( x, inner.positioning = TRUE, outer.positioning = TRUE, - c.labels.inside = F, - flipaxes = c(F, F), + c.labels.inside = FALSE, + flipaxes = c(FALSE, FALSE), strokes.x = 0.1, strokes.y = 0.1, offsetting = TRUE, From 8691bd5a7574b94dc517ac8d6cfdfe00f8583fd7 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 16:12:01 +0200 Subject: [PATCH 03/28] biplot3d: Construct spheres hidden, axews start at origin (#25) `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start at origin now. --- NEWS.md | 5 +++++ R/rgl-3d.r | 16 ++++++++++------ man/biplot3d.Rd | 5 ++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index db7adfd..74477fc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# OpenRepGrid 0.1.18 (dev version) + +* `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start + at origin (#25) + # OpenRepGrid 0.1.17 * `clusterBoot` gains `trim` arg. Construct labels in dendrogram are no longer trimmed by default (#58). diff --git a/R/rgl-3d.r b/R/rgl-3d.r index c65ab5b..636762b 100644 --- a/R/rgl-3d.r +++ b/R/rgl-3d.r @@ -149,6 +149,7 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. lef = 1.1, frame = 1, col.frame = grey(.6), col.sphere = "black", alpha.sphere = .05, zoom = 1, draw.xyz.axes = TRUE, + c.sphere.show = FALSE, # c.points.show=TRUE, # c.labels.show=TRUE, # e.points.show=TRUE, @@ -241,7 +242,9 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. } else { stop("'lines.c' can only take numeric values from 0 to 2") } - rglDrawConstructPoints(cs.p.xyz, c.radius = mval / 200, ...) + if (c.sphere.show) { + rglDrawConstructPoints(cs.p.xyz, c.radius = mval / 200, ...) + } # rglDrawConstructPoints(-Cu[, dim], c.radius=mval/200, ...) # rglDrawStandardEllipses(max.dim) @@ -314,13 +317,13 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' `2 =` lines from the center to outer frame. #' @param lef Construct lines extension factor #' -#' @param center Numeric. The type of centering to be performed. +#' @param center Numeric. The type of centering to be performed. #' 0= no centering, 1= row mean centering (construct), #' 2= column mean centering (elements), 3= double-centering (construct and element means), #' 4= midpoint centering of rows (constructs). #' Default is `1` (row centering). #' -#' @param normalize A numeric value indicating along what direction (rows, columns) +#' @param normalize A numeric value indicating along what direction (rows, columns) #' to normalize by standard deviations. `0 = none, 1= rows, 2 = columns` #' (default is `0`). #' @param g Power of the singular value matrix assigned to the left singular @@ -334,6 +337,7 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' determine the solution. Default is `NA`, i.e. no elements are set #' supplementary. #' +#' @param c.sphere.show Show construct spheres (default is `FALSE`). #' @param c.sphere.col Color of construct spheres. #' @param c.cex Size of construct text. #' @param c.text.col Color for construct text. @@ -396,10 +400,10 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' ) #' } #' -biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = TRUE, +biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = 2, lef = 1.3, center = 1, normalize = 0, g = 0, h = 1, col.active = NA, col.passive = NA, - c.sphere.col = grey(.4), c.cex = .6, c.text.col = grey(.4), + c.sphere.show = FALSE, c.sphere.col = grey(.4), c.cex = .6, c.text.col = grey(.4), e.sphere.col = grey(0), e.cex = .6, e.text.col = grey(0), alpha.sphere = .05, col.sphere = "black", unity = FALSE, @@ -409,7 +413,7 @@ biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = T x = x, dim = dim, labels.e = labels.e, labels.c = labels.c, lines.c = lines.c, lef = lef, center = center, normalize = normalize, g = g, h = h, col.active = col.active, col.passive = col.passive, - c.sphere.col = c.sphere.col, c.cex = c.cex, c.text.col = c.text.col, + c.sphere.show = c.sphere.show, c.sphere.col = c.sphere.col, c.cex = c.cex, c.text.col = c.text.col, e.sphere.col = e.sphere.col, e.cex = e.cex, e.text.col = e.text.col, alpha.sphere = alpha.sphere, col.sphere = col.sphere, unity = unity, unity3d = unity3d, scale.e = scale.e, zoom = zoom, ... diff --git a/man/biplot3d.Rd b/man/biplot3d.Rd index aa927c3..757f3ce 100644 --- a/man/biplot3d.Rd +++ b/man/biplot3d.Rd @@ -9,7 +9,7 @@ biplot3d( dim = 1:3, labels.e = TRUE, labels.c = TRUE, - lines.c = TRUE, + lines.c = 2, lef = 1.3, center = 1, normalize = 0, @@ -17,6 +17,7 @@ biplot3d( h = 1, col.active = NA, col.passive = NA, + c.sphere.show = FALSE, c.sphere.col = grey(0.4), c.cex = 0.6, c.text.col = grey(0.4), @@ -71,6 +72,8 @@ in the SVD but projected into the component space afterwards. They do not determine the solution. Default is \code{NA}, i.e. no elements are set supplementary.} +\item{c.sphere.show}{Show construct spheres (default is \code{FALSE}).} + \item{c.sphere.col}{Color of construct spheres.} \item{c.cex}{Size of construct text.} From 5beb5ae9ce48042f1ff8625239c8b3d64a7eab8b Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 17:59:11 +0200 Subject: [PATCH 04/28] fix `align` function (#22) fix `align` function which caused a bug in `bertinCluster` --- DESCRIPTION | 4 ++-- NEWS.md | 1 + R/calc.r | 13 ++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index af26c8d..e2009e9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,8 +16,8 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.17 -Date: 2025-03-02 +Version: 0.1.18.9001 +Date: 2025-05-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid Imports: diff --git a/NEWS.md b/NEWS.md index 74477fc..7dbf9b1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) +* fix `align` function which caused a bug in `bertinCluster` (#22) * `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start at origin (#25) diff --git a/R/calc.r b/R/calc.r index 9e3d177..6b40e67 100644 --- a/R/calc.r +++ b/R/calc.r @@ -1204,7 +1204,8 @@ cluster <- function(x, along = 0, dmethod = "euclidean", cmethod = "ward.D", p = # function calculates cluster dendrogram from doublebind grid matrix -# and reverses the constructs accoring to the upper big cluster +# by seleting the frist occurence of the reordered grid after clustering +# we (probably) get a decent alignment. NB: Seriation would probably be better. align <- function(x, along = 0, dmethod = "euclidean", cmethod = "ward.D", p = 2, ...) { x2 <- doubleEntry(x) @@ -1212,8 +1213,14 @@ align <- function(x, along = 0, dmethod = "euclidean", dmethod = dmethod, cmethod = cmethod, p = p, align = FALSE, print = FALSE ) - nc <- getNoOfConstructs(xr) / 2 - xr[1:nc, ] + # step 1: cluster by distance + # step 2: take the first occurence of each constructs (see #22) + # => should yield a reasonable alignment. Unclear if it has edge cases. + df_con <- constructs(xr) + l <- as.list(as.data.frame(t(df_con))) # df rows as list + con <- vapply(l, function(x) paste(sort(x), collapse = " "), character(1)) + ii <- which(!duplicated(con)) + xr[ii, ] } From 30a000712494788fb91930a785e3f6b23643452a Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 18:59:29 +0200 Subject: [PATCH 05/28] add tests for fix in align() (#22, #31) --- NEWS.md | 2 +- tests/testthat/test-calc.R | 22 +++++++++ tests/testthat/test_biplot.R | 2 +- tests/testthat/testdata/issue_22.txt | 45 ++++++++++++++++++ tests/testthat/testdata/issue_31.txt | 69 ++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/test-calc.R create mode 100644 tests/testthat/testdata/issue_22.txt create mode 100644 tests/testthat/testdata/issue_31.txt diff --git a/NEWS.md b/NEWS.md index 7dbf9b1..f145425 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) -* fix `align` function which caused a bug in `bertinCluster` (#22) +* fix bug in `align` which caused constructs to disappear and subsequent bugs in `bertinCluster` and `cluster` (#22, #31) * `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start at origin (#25) diff --git a/tests/testthat/test-calc.R b/tests/testthat/test-calc.R new file mode 100644 index 0000000..b2c2ebc --- /dev/null +++ b/tests/testthat/test-calc.R @@ -0,0 +1,22 @@ + +# test for issues #22 and #31 (constructs were missing after align) +test_that("align()", { + + sorted_poles <- function(x) { + df_con <- constructs(x) + l <- as.list(as.data.frame(t(df_con))) # df rows as list + vapply(l, function(x) paste(sort(x), collapse = " "), character(1)) + } + + file <- testthat::test_path("testdata/issue_22.txt") + x <- importTxt(file) + x_aligned <- align(x) + d <- setdiff(sorted_poles(x), sorted_poles(x_aligned)) + expect_length(d, 0) + + file <- testthat::test_path("testdata/issue_31.txt") + x <- importTxt(file) + x_aligned <- align(x) + d <- setdiff(sorted_poles(x), sorted_poles(x_aligned)) + expect_length(d, 0) +}) diff --git a/tests/testthat/test_biplot.R b/tests/testthat/test_biplot.R index c1c81a3..4da8973 100644 --- a/tests/testthat/test_biplot.R +++ b/tests/testthat/test_biplot.R @@ -1,9 +1,9 @@ library(testthat) library(vdiffr) -library(vdiffr) test_that("biplots work", { + create_biplot2d <- function() { set.seed(0) biplot2d(boeker) diff --git a/tests/testthat/testdata/issue_22.txt b/tests/testthat/testdata/issue_22.txt new file mode 100644 index 0000000..fb445a7 --- /dev/null +++ b/tests/testthat/testdata/issue_22.txt @@ -0,0 +1,45 @@ +========================= +Data File for OpenRepGrid +========================= + +ELEMENTS +e-1 +e-2 +e-3 +e-4 +e-5 +e-6 +e-7 +e-8 +e-9 +END ELEMENTS + +CONSTRUCTS +l-1 : r-1 +l-2 : r-2 +l-3 : r-3 +l-4 : r-4 +l-5 : r-5 +l-6 : r-6 +l-7 : r-7 +l-8 : r-8 +l-9 : r-9 +l-10 : r-10 +END CONSTRUCTS + +RATINGS +3 3 4 4 2 3 5 2 4 +1 1 3 2 1 3 4 3 2 +5 5 5 2 1 1 1 4 4 +3 4 2 4 3 3 2 3 3 +5 5 2 3 2 2 3 3 3 +5 5 5 1 1 2 1 5 5 +4 4 4 5 4 3 1 3 1 +5 5 4 5 1 1 4 1 3 +3 4 3 2 1 2 1 3 5 +4 4 3 5 2 2 4 2 2 +END RATINGS + +RANGE +1 5 +END RANGE diff --git a/tests/testthat/testdata/issue_31.txt b/tests/testthat/testdata/issue_31.txt new file mode 100644 index 0000000..c2c0685 --- /dev/null +++ b/tests/testthat/testdata/issue_31.txt @@ -0,0 +1,69 @@ +========================= +Data File for OpenRepGrid +========================= + +ELEMENTS +e-1 +e-2 +e-3 +e-4 +e-5 +e-6 +e-7 +e-8 +e-9 +END ELEMENTS + +CONSTRUCTS +l-1 : r-1 +l-2 : r-2 +l-3 : r-3 +l-4 : r-4 +l-5 : r-5 +l-6 : r-6 +l-7 : r-7 +l-8 : r-8 +l-9 : r-9 +l-10 : r-10 +l-11 : r-11 +l-12 : r-12 +l-13 : r-13 +l-14 : r-14 +l-15 : r-15 +l-16 : r-16 +l-17 : r-17 +l-18 : r-18 +l-19 : r-19 +l-20 : r-20 +l-21 : r-21 +l-22 : r-22 +END CONSTRUCTS + +RATINGS +2 2 2 2 2 2 2 2 3 +1 4 3 1 3 3 2 2 4 +2 3 3 4 2 2 2 1 1 +2 2 4 2 2 2 2 2 2 +3 2 1 2 6 6 4 4 7 +2 3 4 4 2 1 2 2 1 +2 2 3 3 2 1 2 1 1 +2 2 2 2 2 2 3 2 1 +4 6 2 4 4 5 6 4 6 +2 3 3 5 2 2 3 2 2 +2 3 1 1 3 2 2 2 2 +3 3 3 1 4 5 4 4 4 +2 2 3 2 3 3 1 3 2 +2 1 4 4 4 2 2 1 2 +3 3 3 3 3 1 1 2 3 +2 2 3 2 5 5 2 5 6 +3 1 2 1 3 3 2 3 2 +2 2 2 2 2 2 1 1 2 +4 2 2 3 6 3 1 5 4 +2 2 2 1 2 2 2 1 2 +1 1 4 2 2 2 2 3 2 +3 2 3 2 3 3 3 3 2 +END RATINGS + +RANGE +1 7 +END RANGE From 14fb32614ef34839a2347e2cec45e29c2e58ab1f Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 19:15:02 +0200 Subject: [PATCH 06/28] `distanceHartmann`: `method` arg default now `simulate` (#19) --- DESCRIPTION | 2 +- NEWS.md | 1 + R/distance.R | 4 ++-- man/distanceHartmann.Rd | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index e2009e9..24daaa6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9001 +Version: 0.1.18.9002 Date: 2025-05-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/NEWS.md b/NEWS.md index f145425..8fc5f85 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) +* `distanceHartmann`: change default for `method` arg to `simulate` (#19) * fix bug in `align` which caused constructs to disappear and subsequent bugs in `bertinCluster` and `cluster` (#22, #31) * `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start at origin (#25) diff --git a/R/distance.R b/R/distance.R index 55c9dab..2860170 100644 --- a/R/distance.R +++ b/R/distance.R @@ -449,7 +449,7 @@ getDistributionParameters <- function(x, probs = c(.01, .025, .05, .1, .9, .95, #' parameters as given in Hartmann (1992) for calculation. #' `"simulate"` (default) simulates a Slater distribution #' for the calculation. In a future version the time consuming -#' simulation will be replaced by more accurate parameters for +#' simulation may be replaced by more accurate parameters for #' Hartmann distances than used in Hartmann (1992). #' @param reps Number of random grids to generate sample distribution for #' Slater distances (default is `10000`). Note that @@ -501,7 +501,7 @@ getDistributionParameters <- function(x, probs = c(.01, .025, .05, .1, .9, .95, #' hist(l$hartmann, breaks = 100) #' } #' -distanceHartmann <- function(x, method = "paper", reps = 10000, +distanceHartmann <- function(x, method = "simulate", reps = 10000, prob = NULL, progress = TRUE, distributions = FALSE) { if (distributions == TRUE & method != "simulate") { method <- "simulate" diff --git a/man/distanceHartmann.Rd b/man/distanceHartmann.Rd index 527c8a3..40ff949 100644 --- a/man/distanceHartmann.Rd +++ b/man/distanceHartmann.Rd @@ -6,7 +6,7 @@ \usage{ distanceHartmann( x, - method = "paper", + method = "simulate", reps = 10000, prob = NULL, progress = TRUE, @@ -21,7 +21,7 @@ distanceHartmann( parameters as given in Hartmann (1992) for calculation. \code{"simulate"} (default) simulates a Slater distribution for the calculation. In a future version the time consuming -simulation will be replaced by more accurate parameters for +simulation may be replaced by more accurate parameters for Hartmann distances than used in Hartmann (1992).} \item{reps}{Number of random grids to generate sample distribution for From 19c33d2f94b7909065fd7cf9bd38273c5838ce5c Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 19:26:17 +0200 Subject: [PATCH 07/28] print.distance(): fix docs for `cutoffs` arg (#18) --- DESCRIPTION | 2 +- NEWS.md | 1 + R/distance.R | 5 ++--- man/print.distance.Rd | 5 ++--- man/print.hdistance.Rd | 5 ++--- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 24daaa6..b363e28 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9002 +Version: 0.1.18.9003 Date: 2025-05-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/NEWS.md b/NEWS.md index 8fc5f85..a681f78 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) +* `print.distance`: fix docs for `cutoffs` arg (#18) * `distanceHartmann`: change default for `method` arg to `simulate` (#19) * fix bug in `align` which caused constructs to disappear and subsequent bugs in `bertinCluster` and `cluster` (#22, #31) * `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start diff --git a/R/distance.R b/R/distance.R index 2860170..d5c74d3 100644 --- a/R/distance.R +++ b/R/distance.R @@ -125,9 +125,8 @@ dist_minmax <- function(x, along = 1, dmethod = "euclidean", p = 2, max.only = F #' the output (default is `TRUE`). #' @param upper Whether to display upper triangle of correlation matrix only #' (default is `TRUE`). -#' @param cutoffs Cutoff values. Values below or above this interval are not -#' printed. For Slater distances `c(.8, 1.2)` are common -#' values. +#' @param cutoffs Cutoff values. Only values outside the interval are printed. +#' For Slater distances `c(.8, 1.2)` are common values. #' @param diag Whether to show the matrix diagonal. #' @param ... Not evaluated. #' @export diff --git a/man/print.distance.Rd b/man/print.distance.Rd index de307f7..9fa370d 100644 --- a/man/print.distance.Rd +++ b/man/print.distance.Rd @@ -30,9 +30,8 @@ the output (default is \code{TRUE}).} \item{diag}{Whether to show the matrix diagonal.} -\item{cutoffs}{Cutoff values. Values below or above this interval are not -printed. For Slater distances \code{c(.8, 1.2)} are common -values.} +\item{cutoffs}{Cutoff values. Only values outside the interval are printed. +For Slater distances \code{c(.8, 1.2)} are common values.} \item{...}{Not evaluated.} } diff --git a/man/print.hdistance.Rd b/man/print.hdistance.Rd index 2417d6e..055e03f 100644 --- a/man/print.hdistance.Rd +++ b/man/print.hdistance.Rd @@ -31,9 +31,8 @@ the output (default is \code{TRUE}).} \item{diag}{Whether to show the matrix diagonal.} -\item{cutoffs}{Cutoff values. Values below or above this interval are not -printed. For Slater distances \code{c(.8, 1.2)} are common -values.} +\item{cutoffs}{Cutoff values. Only values outside the interval are printed. +For Slater distances \code{c(.8, 1.2)} are common values.} \item{p}{Quantiles corresponding to probabilities are used as cutoffs. Currently only works for Hartmann distances. If used \code{cutoffs} is overwritten.} From c62399b4af058a32d866566a1a313224884b727a Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 19:59:31 +0200 Subject: [PATCH 08/28] biplot3d: add args `e.sphere.show`, `e.labels.show` (#9) --- DESCRIPTION | 2 +- R/rgl-3d.r | 15 +++++++++++++-- man/biplot3d.Rd | 12 ++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b363e28..01e28ad 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9003 +Version: 0.1.18.9004 Date: 2025-05-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/R/rgl-3d.r b/R/rgl-3d.r index 636762b..593ff64 100644 --- a/R/rgl-3d.r +++ b/R/rgl-3d.r @@ -224,7 +224,7 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. if (lines.c == 0) { # no construct lines labels at cons pos rglDrawConstructLabels(cl.l.xyz, labels = cs.l$label, ...) - if (draw.xyz.axes) rglDrawStandardAxes(mval, spheres = F) + if (draw.xyz.axes) rglDrawStandardAxes(mval, spheres = FALSE) # rglDrawConstructLabels(Cu[, dim], labels=labels.r, ...) # rglDrawConstructLabels(-Cu[, dim], labels=labels.l, ...) } else if (lines.c == 1) { # construct lines from cons pos to outside @@ -341,7 +341,14 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' @param c.sphere.col Color of construct spheres. #' @param c.cex Size of construct text. #' @param c.text.col Color for construct text. -#' +#' @param e.sphere.show Whether the elements are printed (default is `TRUE`). +#' `FALSE` will suppress the printing of the elements. +#' To only print certain elements a numeric vector can be +#' provided (e.g. `c(1:10)`). +#' @param e.labels.show Whether the element labels are printed (default is `TRUE`). +#' `FALSE` will suppress the printing of the labels. +#' To only print certain element labels a numeric vector can be +#' provided (e.g. `c(1:10)`). #' @param e.sphere.col Color of elements. #' @param e.cex Size of element labels. #' @param e.text.col Color of element labels. @@ -403,7 +410,9 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = 2, lef = 1.3, center = 1, normalize = 0, g = 0, h = 1, col.active = NA, col.passive = NA, + #c.points.show = TRUE, c.labels.show = TRUE, c.sphere.show = FALSE, c.sphere.col = grey(.4), c.cex = .6, c.text.col = grey(.4), + e.sphere.show = TRUE, e.labels.show = TRUE, e.sphere.col = grey(0), e.cex = .6, e.text.col = grey(0), alpha.sphere = .05, col.sphere = "black", unity = FALSE, @@ -413,7 +422,9 @@ biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = 2 x = x, dim = dim, labels.e = labels.e, labels.c = labels.c, lines.c = lines.c, lef = lef, center = center, normalize = normalize, g = g, h = h, col.active = col.active, col.passive = col.passive, + #c.points.show = c.points.show, c.labels.show = c.labels.show, c.sphere.show = c.sphere.show, c.sphere.col = c.sphere.col, c.cex = c.cex, c.text.col = c.text.col, + e.points.show = e.sphere.show, e.labels.show = e.labels.show, e.sphere.col = e.sphere.col, e.cex = e.cex, e.text.col = e.text.col, alpha.sphere = alpha.sphere, col.sphere = col.sphere, unity = unity, unity3d = unity3d, scale.e = scale.e, zoom = zoom, ... diff --git a/man/biplot3d.Rd b/man/biplot3d.Rd index 757f3ce..54e1010 100644 --- a/man/biplot3d.Rd +++ b/man/biplot3d.Rd @@ -21,6 +21,8 @@ biplot3d( c.sphere.col = grey(0.4), c.cex = 0.6, c.text.col = grey(0.4), + e.sphere.show = TRUE, + e.labels.show = TRUE, e.sphere.col = grey(0), e.cex = 0.6, e.text.col = grey(0), @@ -80,6 +82,16 @@ supplementary.} \item{c.text.col}{Color for construct text.} +\item{e.sphere.show}{Whether the elements are printed (default is \code{TRUE}). +\code{FALSE} will suppress the printing of the elements. +To only print certain elements a numeric vector can be +provided (e.g. \code{c(1:10)}).} + +\item{e.labels.show}{Whether the element labels are printed (default is \code{TRUE}). +\code{FALSE} will suppress the printing of the labels. +To only print certain element labels a numeric vector can be +provided (e.g. \code{c(1:10)}).} + \item{e.sphere.col}{Color of elements.} \item{e.cex}{Size of element labels.} From a3091350d290561c6ad6724c63ada3fe66c6d70c Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 20:48:23 +0200 Subject: [PATCH 09/28] biplot3d: new args c.axis.show, c.sphere.show (#9) --- DESCRIPTION | 2 +- R/rgl-3d.r | 77 ++++++++++---------------------- inst/examples/example-biplot3d.R | 13 ++++++ man/biplot3d.Rd | 30 ++++++------- 4 files changed, 51 insertions(+), 71 deletions(-) create mode 100644 inst/examples/example-biplot3d.R diff --git a/DESCRIPTION b/DESCRIPTION index 01e28ad..acc37e3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9004 +Version: 0.1.18.9005 Date: 2025-05-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/R/rgl-3d.r b/R/rgl-3d.r index 593ff64..8d2a853 100644 --- a/R/rgl-3d.r +++ b/R/rgl-3d.r @@ -148,13 +148,8 @@ rglDrawConstructLabels <- function(coords, labels = FALSE, dim = 1:3, biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = 1, lef = 1.1, frame = 1, col.frame = grey(.6), col.sphere = "black", alpha.sphere = .05, zoom = 1, - draw.xyz.axes = TRUE, - c.sphere.show = FALSE, - # c.points.show=TRUE, - # c.labels.show=TRUE, - # e.points.show=TRUE, - # e.labels.show=TRUE, - ...) { + draw.xyz.axes = TRUE, ...) { + if (!requireNamespace("rgl", quietly = TRUE)) { stop("The 'rgl' package is required to use OpenRepGrid's 3D features => please install 'rgl'.", call. = FALSE) } @@ -242,9 +237,7 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. } else { stop("'lines.c' can only take numeric values from 0 to 2") } - if (c.sphere.show) { - rglDrawConstructPoints(cs.p.xyz, c.radius = mval / 200, ...) - } + rglDrawConstructPoints(cs.p.xyz, c.radius = mval / 200, ...) # rglDrawConstructPoints(-Cu[, dim], c.radius=mval/200, ...) # rglDrawStandardEllipses(max.dim) @@ -316,13 +309,11 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' `0 =` no lines, `1 =` lines from constructs to outer frame, #' `2 =` lines from the center to outer frame. #' @param lef Construct lines extension factor -#' #' @param center Numeric. The type of centering to be performed. #' 0= no centering, 1= row mean centering (construct), #' 2= column mean centering (elements), 3= double-centering (construct and element means), #' 4= midpoint centering of rows (constructs). #' Default is `1` (row centering). -#' #' @param normalize A numeric value indicating along what direction (rows, columns) #' to normalize by standard deviations. `0 = none, 1= rows, 2 = columns` #' (default is `0`). @@ -336,26 +327,25 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' in the SVD but projected into the component space afterwards. They do not #' determine the solution. Default is `NA`, i.e. no elements are set #' supplementary. -#' -#' @param c.sphere.show Show construct spheres (default is `FALSE`). +#' @param c.axis.show Whether the construct axes are shown (default is `TRUE`). +#' `FALSE` will suppress the printing all axes. +#' To only print certain axes, a numeric vector can be provided (e.g. `c(1:10)`). +#' @param c.sphere.show Whether the construct speheres are shown (default is `FALSE`). +#' To only print certain speheres, a numeric vector can be provided (e.g. `c(1:10)`). #' @param c.sphere.col Color of construct spheres. #' @param c.cex Size of construct text. #' @param c.text.col Color for construct text. #' @param e.sphere.show Whether the elements are printed (default is `TRUE`). #' `FALSE` will suppress the printing of the elements. -#' To only print certain elements a numeric vector can be -#' provided (e.g. `c(1:10)`). +#' To only print certain elements, a numeric vector can be provided (e.g. `c(1:10)`). #' @param e.labels.show Whether the element labels are printed (default is `TRUE`). #' `FALSE` will suppress the printing of the labels. -#' To only print certain element labels a numeric vector can be -#' provided (e.g. `c(1:10)`). +#' To only print certain element labels, a numeric vector can be provided (e.g. `c(1:10)`). #' @param e.sphere.col Color of elements. #' @param e.cex Size of element labels. #' @param e.text.col Color of element labels. -#' #' @param alpha.sphere Numeric. alpha blending of the surrounding sphere (default`".05"`). #' @param col.sphere Color of surrounding sphere (default`"black"`). -#' #' @param unity Scale elements and constructs coordinates to unit scale (maximum of 1) #' so they are printed more neatly (default `TRUE`). #' @param unity3d To come. @@ -365,6 +355,7 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' @param zoom Not yet used. Scaling factor for all vectors. Can be used to zoom #' the plot in and out (default `1`). #' @param ... Parameters to be passed on. +#' #' @export #' @seealso Unsophisticated biplot: [biplotSimple()]; \cr #' 2D biplots: @@ -382,48 +373,26 @@ biplot3dBase2 <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines. #' Function to set view in 3D: #' [home()]. #' -#' @references Raeithel, A. (1998). Kooperative Modellproduktion von -#' Professionellen und Klienten - erlauetert am Beispiel des -#' Repertory Grid. *Selbstorganisation, Kooperation, Zeichenprozess: -#' Arbeiten zu einer kulturwissenschaftlichen, anwendungsbezogenen -#' Psychologie* (pp. 209-254). Opladen: Westdeutscher Verlag. -#' -#' @examples \dontrun{ -#' -#' biplot3d(boeker) -#' biplot3d(boeker, unity3d = T) +#' @references Raeithel, A. (1998). Kooperative Modellproduktion von +#' Professionellen und Klienten - erlauetert am Beispiel des +#' Repertory Grid. *Selbstorganisation, Kooperation, Zeichenprozess: +#' Arbeiten zu einer kulturwissenschaftlichen, anwendungsbezogenen +#' Psychologie* (pp. 209-254). Opladen: Westdeutscher Verlag. #' -#' biplot3d(boeker, -#' e.sphere.col = "red", -#' c.text.col = "blue" -#' ) -#' biplot3d(boeker, e.cex = 1) -#' biplot3d(boeker, col.sphere = "red") -#' -#' biplot3d(boeker, g = 1, h = 1) # INGRID biplot -#' biplot3d(boeker, -#' g = 1, h = 1, # ESA biplot -#' center = 4 -#' ) -#' } +#' @example inst/examples/example-biplot3d.R #' biplot3d <- function(x, dim = 1:3, labels.e = TRUE, labels.c = TRUE, lines.c = 2, - lef = 1.3, center = 1, normalize = 0, g = 0, h = 1, col.active = NA, - col.passive = NA, - #c.points.show = TRUE, c.labels.show = TRUE, - c.sphere.show = FALSE, c.sphere.col = grey(.4), c.cex = .6, c.text.col = grey(.4), - e.sphere.show = TRUE, e.labels.show = TRUE, - e.sphere.col = grey(0), e.cex = .6, e.text.col = grey(0), + lef = 1.3, center = 1, normalize = 0, g = 0, h = 1, col.active = NA, col.passive = NA, + c.axis.show = TRUE, c.sphere.show = FALSE, c.sphere.col = grey(.4), c.cex = .6, c.text.col = grey(.4), + e.sphere.show = TRUE, e.labels.show = TRUE, e.sphere.col = grey(0), e.cex = .6, e.text.col = grey(0), alpha.sphere = .05, col.sphere = "black", - unity = FALSE, - unity3d = FALSE, - scale.e = .9, zoom = 1, ...) { + unity = FALSE, unity3d = FALSE, scale.e = .9, zoom = 1, ...) { biplot3dBase2( x = x, dim = dim, labels.e = labels.e, labels.c = labels.c, lines.c = lines.c, lef = lef, center = center, normalize = normalize, g = g, h = h, col.active = col.active, col.passive = col.passive, - #c.points.show = c.points.show, c.labels.show = c.labels.show, - c.sphere.show = c.sphere.show, c.sphere.col = c.sphere.col, c.cex = c.cex, c.text.col = c.text.col, + c.points.show = c.sphere.show, c.labels.show = c.axis.show, + c.sphere.col = c.sphere.col, c.cex = c.cex, c.text.col = c.text.col, e.points.show = e.sphere.show, e.labels.show = e.labels.show, e.sphere.col = e.sphere.col, e.cex = e.cex, e.text.col = e.text.col, alpha.sphere = alpha.sphere, col.sphere = col.sphere, diff --git a/inst/examples/example-biplot3d.R b/inst/examples/example-biplot3d.R new file mode 100644 index 0000000..6b3f01e --- /dev/null +++ b/inst/examples/example-biplot3d.R @@ -0,0 +1,13 @@ +\dontrun{ +biplot3d(boeker) + +biplot3d(boeker, e.sphere.show = 1:4) +biplot3d(boeker, c.axis.show = 1:2) + +biplot3d(boeker, e.sphere.col = "red", c.text.col = "blue") +biplot3d(boeker, e.cex = 1) +biplot3d(boeker, col.sphere = "red") + +biplot3d(boeker, g = 1, h = 1) # INGRID biplot +biplot3d(boeker, g = 1, h = 1, center = 4) # ESA biplot +} diff --git a/man/biplot3d.Rd b/man/biplot3d.Rd index 54e1010..8839b54 100644 --- a/man/biplot3d.Rd +++ b/man/biplot3d.Rd @@ -17,6 +17,7 @@ biplot3d( h = 1, col.active = NA, col.passive = NA, + c.axis.show = TRUE, c.sphere.show = FALSE, c.sphere.col = grey(0.4), c.cex = 0.6, @@ -74,7 +75,12 @@ in the SVD but projected into the component space afterwards. They do not determine the solution. Default is \code{NA}, i.e. no elements are set supplementary.} -\item{c.sphere.show}{Show construct spheres (default is \code{FALSE}).} +\item{c.axis.show}{Whether the construct axes are shown (default is \code{TRUE}). +\code{FALSE} will suppress the printing all axes. +To only print certain axes, a numeric vector can be provided (e.g. \code{c(1:10)}).} + +\item{c.sphere.show}{Whether the construct speheres are shown (default is \code{FALSE}). +To only print certain speheres, a numeric vector can be provided (e.g. \code{c(1:10)}).} \item{c.sphere.col}{Color of construct spheres.} @@ -84,13 +90,11 @@ supplementary.} \item{e.sphere.show}{Whether the elements are printed (default is \code{TRUE}). \code{FALSE} will suppress the printing of the elements. -To only print certain elements a numeric vector can be -provided (e.g. \code{c(1:10)}).} +To only print certain elements, a numeric vector can be provided (e.g. \code{c(1:10)}).} \item{e.labels.show}{Whether the element labels are printed (default is \code{TRUE}). \code{FALSE} will suppress the printing of the labels. -To only print certain element labels a numeric vector can be -provided (e.g. \code{c(1:10)}).} +To only print certain element labels, a numeric vector can be provided (e.g. \code{c(1:10)}).} \item{e.sphere.col}{Color of elements.} @@ -128,24 +132,18 @@ of elements under investigation (e.g. Raeithel, 1998). } \examples{ \dontrun{ - biplot3d(boeker) -biplot3d(boeker, unity3d = T) -biplot3d(boeker, - e.sphere.col = "red", - c.text.col = "blue" -) +biplot3d(boeker, e.sphere.show = 1:4) +biplot3d(boeker, c.axis.show = 1:2) + +biplot3d(boeker, e.sphere.col = "red", c.text.col = "blue") biplot3d(boeker, e.cex = 1) biplot3d(boeker, col.sphere = "red") biplot3d(boeker, g = 1, h = 1) # INGRID biplot -biplot3d(boeker, - g = 1, h = 1, # ESA biplot - center = 4 -) +biplot3d(boeker, g = 1, h = 1, center = 4) # ESA biplot } - } \references{ Raeithel, A. (1998). Kooperative Modellproduktion von From 54e053b01a7487d6f0d931e05a1cd1aad8c9cabb Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 20:51:02 +0200 Subject: [PATCH 10/28] biplot3d: arg `e.labels.show` --- inst/examples/example-biplot3d.R | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/examples/example-biplot3d.R b/inst/examples/example-biplot3d.R index 6b3f01e..1254be6 100644 --- a/inst/examples/example-biplot3d.R +++ b/inst/examples/example-biplot3d.R @@ -2,6 +2,7 @@ biplot3d(boeker) biplot3d(boeker, e.sphere.show = 1:4) +biplot3d(boeker, e.sphere.show = 1:4, e.labels.show = 1:2) biplot3d(boeker, c.axis.show = 1:2) biplot3d(boeker, e.sphere.col = "red", c.text.col = "blue") From 3ca337d96a804af1173bdbf691826e66c2aaf53e Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Thu, 8 May 2025 20:56:16 +0200 Subject: [PATCH 11/28] biplot3d: add to NEWS.md, tweak example --- NEWS.md | 4 ++-- man/biplot3d.Rd | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a681f78..2c86e63 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,10 +1,10 @@ # OpenRepGrid 0.1.18 (dev version) +* `biplot3d`: New args `e.sphere.show`, `e.labels.show`, `c.axis.show`. `c.sphere.show`. Construct spheres now hidden + by default. Construct axes start at origin (#9, #25) * `print.distance`: fix docs for `cutoffs` arg (#18) * `distanceHartmann`: change default for `method` arg to `simulate` (#19) * fix bug in `align` which caused constructs to disappear and subsequent bugs in `bertinCluster` and `cluster` (#22, #31) -* `biplot3d`: New arg `c.sphere.show` and new defaults: Construct spheres now hidden by default, construct axes start - at origin (#25) # OpenRepGrid 0.1.17 diff --git a/man/biplot3d.Rd b/man/biplot3d.Rd index 8839b54..e1e9aed 100644 --- a/man/biplot3d.Rd +++ b/man/biplot3d.Rd @@ -135,6 +135,7 @@ of elements under investigation (e.g. Raeithel, 1998). biplot3d(boeker) biplot3d(boeker, e.sphere.show = 1:4) +biplot3d(boeker, e.sphere.show = 1:4, e.labels.show = 1:2) biplot3d(boeker, c.axis.show = 1:2) biplot3d(boeker, e.sphere.col = "red", c.text.col = "blue") From 0fecfb24b531f71cfbeae4fe1e4a1eb81bb1e44f Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Fri, 4 Jul 2025 19:46:35 +0200 Subject: [PATCH 12/28] settings(): increase `show.cut` default to 25 --- R/settings.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/settings.r b/R/settings.r index 55a9865..bba3901 100644 --- a/R/settings.r +++ b/R/settings.r @@ -5,7 +5,7 @@ generateDefaultSettings <- function() { # print grid to console l$show.trim <- 30 type$show.trim <- "numeric" - l$show.cut <- 20 + l$show.cut <- 25 type$show.cut <- "numeric" l$show.scale <- TRUE type$show.scale <- "logical" From 2b9dc8761398ef91d09318907d49ca2457762c7c Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Sat, 5 Jul 2025 09:33:17 +0200 Subject: [PATCH 13/28] `bertinCluster` now restores original `par()` settings (fix #63) `bertinCluster`: now restores the original `par()` settings after changing the plot layout (#63). Before this caused problems in subsequent plots, as `par(new = TRUE)` remained set. --- DESCRIPTION | 4 ++-- NEWS.md | 1 + R/bertin.r | 20 ++++---------------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1289d6b..af8e6c6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,8 +16,8 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9006 -Date: 2025-05-12 +Version: 0.1.18.9007 +Date: 2025-07-04 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid Imports: diff --git a/NEWS.md b/NEWS.md index fa1fdb0..0d1cdf4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) +* `bertinCluster`: now restores the original `par()` settings after changing the plot layout (#63). * `importTxt` reads preferred poles from section `PREFERRED`, `importExcel` reads rightmost column `preferred_poles` (#57) * `preferredPoles` sets the preferred construct poles, `preferredPolesByIdeal` sets the preferred pole bases on the ideal elements ratings, `alignByPreferredPole` aligns constructs by pole preference (#57) diff --git a/R/bertin.r b/R/bertin.r index 9ac5f1f..dd011eb 100644 --- a/R/bertin.r +++ b/R/bertin.r @@ -786,16 +786,14 @@ bertinCluster <- function(x, dmethod = c("euclidean", "euclidean"), x <- x[con.ord, el.ord] # reorder repgrid object + old_par <- par(fig = c(xsegs[c(1, 4)], ysegs[c(2, 4)])) plot.new() - par(fig = c(xsegs[c(1, 4)], ysegs[c(2, 4)]), new = TRUE) - # par(fig = c(0, .8, .2, 1), new=T) - - bertin(x, xlim = xlim.bertin, ylim = ylim.bertin, add = TRUE, ...) # print reordered bertin + bertin(x, xlim = xlim.bertin, ylim = ylim.bertin, add = FALSE, ...) # print reordered bertin # x dendrogram (horizontal) elements if (!is.na(cmethod[2])) { dend.x.fig <- c(xsegs[2:3], ysegs[1:2]) + c(0, 0, y.off, -y.off) # adjust for offsets - par(fig = dend.x.fig, new = T, mar = c(0, 0, 0, 0)) + par(fig = dend.x.fig, new = TRUE, mar = c(0, 0, 0, 0)) # trick: new = TRUE avoids opening a new plot window in next plot ymax.el <- attr(dend.el, "height") plot(dend.el, horiz = F, xlab = "", xaxs = "i", yaxs = "i", yaxt = "n", @@ -819,17 +817,7 @@ bertinCluster <- function(x, dmethod = c("euclidean", "euclidean"), axis(1, las = 1, cex.axis = cex.axis, col = col.axis, col.axis = col.axis) } } + par(old_par) # return hclust objects for elements and constructs invisible(list(constructs = fit.constructs, elements = fit.elements)) } - -# TODO: use of layout does not work with bertinCluster -# a future version could use layout -# layout (matrix(1:4), 2) -# bertinCluster(bell2010) - -# bertinCluster(bell2010, type="t", bor=grey(.5)) -# dev.new() -# bertinCluster(bell2010, type="t", dm="manhattan", cm="single") -# dev.new() -# bertinCluster(bell2010, type="t", dm="manhattan", cm="centroid") From 795757678b3e935f6c3438b10eb3d2686d14f06c Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Sat, 5 Jul 2025 13:16:59 +0200 Subject: [PATCH 14/28] feat: saveAsExcel() with `format` arg for wide output (close #64). `saveAsExcel` now supports output in wide and long format. The output is also formatted now. --- DESCRIPTION | 4 +- NEWS.md | 1 + R/export.r | 124 ++++++++++++++++++++++++++++++++++++--------- R/utils.r | 9 ++++ man/saveAsExcel.Rd | 31 ++++++++---- 5 files changed, 131 insertions(+), 38 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index af8e6c6..a2883a0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,8 +16,8 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9007 -Date: 2025-07-04 +Version: 0.1.18.9008 +Date: 2025-07-05 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid Imports: diff --git a/NEWS.md b/NEWS.md index 0d1cdf4..d547d0f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 (dev version) +* `saveAsExcel` now supports output in wide and long format. The output is also formatted now (#64). * `bertinCluster`: now restores the original `par()` settings after changing the plot layout (#63). * `importTxt` reads preferred poles from section `PREFERRED`, `importExcel` reads rightmost column `preferred_poles` (#57) * `preferredPoles` sets the preferred construct poles, `preferredPolesByIdeal` sets the preferred pole bases on the diff --git a/R/export.r b/R/export.r index ee03828..db5875f 100644 --- a/R/export.r +++ b/R/export.r @@ -171,44 +171,118 @@ saveAsTxt <- function(x, file = NA) { ############################# EXPORT EXCEL #################################### -#' Save grid in a Microsoft Excel file (.xlsx) +#' Save grid as Microsoft Excel file (.xlsx) #' -#' `saveAsExcel` will save the grid as a Microsoft Excel file -#' (`.xlsx`). +#' `saveAsExcel` will save the grid as a Microsoft Excel file (`.xlsx`). #' -#' @param x A `repgrid` object. -#' @param file Filename to save the grid to. The name should have -#' the suffix `.xlsx`. -#' @param sheet Index of the sheet to write to. -#' @return Invisibly returns the name of the file. +#' @param x A `repgrid` object. +#' @param file File path. Suffix must be `.xlsx`. +#' @param format Two output formats are supported: `wide` (default) where each column represents one element, each row +#' represent one constructs (a common grid representation), and `long` where each row contains an element-construct +#' combination and the corresponding rating value. See [importExcel()] for details and examples. +#' @param sheet Optional sheet name. If `NULL` (default), either `"grid (wide format)"` or `"grid (long format)"`. +#' @return Invisibly returns file path. #' @export #' @seealso [importExcel()] -#' @examples \dontrun{ -#' -#' x <- randomGrid(options = 0) -#' saveAsExcel(x, "grid.xlsx") +#' @examples +#' # save grid in wide format (default) +#' file <- tempfile(fileext = ".xlsx") +#' saveAsExcel(boeker, file) +#' \dontrun{ +#' browseURL(file) # open file, requires Excel, may not work on all system #' } #' -saveAsExcel <- function(x, file, sheet = 1) { - # check for correct file extension +#' # save grid in log format +#' file <- tempfile(fileext = ".xlsx") +#' saveAsExcel(boeker, file, format = "long") +#' \dontrun{ +#' browseURL(file) +#' } +saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { + stop_if_not_is_repgrid(x) ext <- tools::file_ext(file) if (ext != "xlsx") { - stop("The file extension must be '.xlsx' but you have '.", ext, "'", call. = FALSE) + stop("The file extension must be '.xlsx'. Found '", ext, "' instead.", call. = FALSE) } + format <- match.arg(tolower(format), c("wide", "long")) + + if (format == "wide") { + df <- grid_to_wide_format(x) + sheet <- sheet %||% "grid (wide format)" + jj_rows <- seq_len(nrow(df) + 1) + jj_elements <- seq_len(ncol(x)) + 1 + j_left_pole <- 1 + j_right_pole <- ncol(x) + 2 + j_preferred <- ncol(df) + + style_header <- openxlsx::createStyle(textDecoration = "bold", fgFill = "grey90", border = "bottom") + style_center <- openxlsx::createStyle(halign = "center") + style_pole_left <- openxlsx::createStyle(textDecoration = "bold", halign = "right", border = "right") + style_pole_right <- openxlsx::createStyle(textDecoration = "bold", halign = "left", border = "left") + style_text_grey <- openxlsx::createStyle(fontColour = "grey50") + + wb <- openxlsx::createWorkbook() + + openxlsx::addWorksheet(wb, sheet) + openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) + openxlsx::addStyle(wb, sheet, style = style_center, rows = jj_rows, cols = jj_elements, stack = TRUE, gridExpand = TRUE) + openxlsx::addStyle(wb, sheet, style = style_pole_left, rows = jj_rows, cols = j_left_pole, stack = TRUE, gridExpand = TRUE) + openxlsx::addStyle(wb, sheet, style = style_pole_right, rows = jj_rows, cols = j_right_pole, stack = TRUE, gridExpand = TRUE) + openxlsx::addStyle(wb, sheet, style = style_text_grey, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) + openxlsx::setColWidths(wb, sheet, cols = c(j_left_pole, j_right_pole, j_preferred), widths = c(20, 20, 13)) + openxlsx::saveWorkbook(wb, file, overwrite = TRUE) + } else { + df <- grid_to_long_format(x) + sheet <- sheet %||% "grid (long format)" + jj_rows <- seq_len(nrow(df) + 1) + jj_cols <- seq_len(ncol(df)) + jj_cols_optional <- 5:7 + j_preferred <- 5 + ii_end_construct <- rle(df$left_pole)$lengths %>% cumsum() %>% head(-1) + 1 - # build matrix to write to Excel + style_header <- openxlsx::createStyle(textDecoration = "bold", fgFill = "grey90", border = "bottom") + style_border_left <- openxlsx::createStyle(border = "left") + style_border_bottom <- openxlsx::createStyle(border = "bottom", borderStyle = "dashed") + style_text_grey <- openxlsx::createStyle(fontColour = "grey50") + + wb <- openxlsx::createWorkbook() + sheet <- "grid (long format)" + openxlsx::addWorksheet(wb, sheet) + openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) + openxlsx::addStyle(wb, sheet, style = style_border_left, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) + openxlsx::addStyle(wb, sheet, style = style_text_grey, rows = jj_rows, cols = jj_cols_optional, stack = TRUE, gridExpand = TRUE) + openxlsx::addStyle(wb, sheet, style = style_border_bottom, rows = ii_end_construct, cols = jj_cols, stack = TRUE, gridExpand = TRUE) + openxlsx::setColWidths(wb, sheet, cols = jj_cols, widths = c(20, 20, 20, 10, 13, 10, 10)) + openxlsx::freezePane(wb, sheet, firstActiveRow = 2) + openxlsx::saveWorkbook(wb, file, overwrite = TRUE) + } + invisible(file) +} + + +grid_to_wide_format <- function(x) { enames <- elements(x) cnames <- constructs(x) - scores <- ratings(x, names = FALSE) - mm <- getScale(x) # min, max + ratings <- ratings(x, names = FALSE) + min_max <- getScale(x) + preferred_pole <- preferredPoles(x) - part1 <- c(mm[1], enames, mm[2]) - part2 <- cbind(cnames$leftpole, scores, cnames$rightpole) - m <- rbind(part1, part2) - m <- unname(m) + df <- cbind(cnames$leftpole, as.data.frame(ratings), cnames$rightpole, preferred_pole) + names(df) <- c(min_max[1], enames, min_max[2], "preferred_pole") + df +} - # write to disk - openxlsx::write.xlsx(m, file, colNames = FALSE, rowNames = FALSE, sheet = sheet) - invisible(file) +grid_to_long_format <- function(x) { + element <- left_pole <- right_pole <- preferred_pole <- NULL # register for R CMD CHECK + df <- grid_to_wide_format(x) + names(df)[c(1L, ncol(x) + 2)] <- c("left_pole", "right_pole") + df_long <- df %>% + tidyr::pivot_longer(-c(left_pole, right_pole, preferred_pole), names_to = "element", values_to = "rating") + rmin <- getScale(x)["min"] + rmax <- getScale(x)["max"] + df_long <- df_long %>% + dplyr::select(element, left_pole, right_pole, rating, preferred_pole) %>% + dplyr::mutate(rmin = rmin, rmax = rmax) + df_long } diff --git a/R/utils.r b/R/utils.r index 1851bfd..7455d5e 100644 --- a/R/utils.r +++ b/R/utils.r @@ -1021,3 +1021,12 @@ list_to_dataframe <- function(l) { # plyr:::list_to_dataframe(l) do.call(rbind.data.frame, l) } + + +`%||%` <- function(a, b){ + if (!is.null(a)) { + a + } else { + b + } +} diff --git a/man/saveAsExcel.Rd b/man/saveAsExcel.Rd index 39b7b19..cb11e2a 100644 --- a/man/saveAsExcel.Rd +++ b/man/saveAsExcel.Rd @@ -2,32 +2,41 @@ % Please edit documentation in R/export.r \name{saveAsExcel} \alias{saveAsExcel} -\title{Save grid in a Microsoft Excel file (.xlsx)} +\title{Save grid as Microsoft Excel file (.xlsx)} \usage{ -saveAsExcel(x, file, sheet = 1) +saveAsExcel(x, file, format = "wide", sheet = NULL) } \arguments{ \item{x}{A \code{repgrid} object.} -\item{file}{Filename to save the grid to. The name should have -the suffix \code{.xlsx}.} +\item{file}{File path. Suffix must be \code{.xlsx}.} -\item{sheet}{Index of the sheet to write to.} +\item{format}{Two output formats are supported: \code{wide} (default) where each column represents one element, each row +represent one constructs (a common grid representation), and \code{long} where each row contains an element-construct +combination and the corresponding rating value. See \code{\link[=importExcel]{importExcel()}} for details and examples.} + +\item{sheet}{Optional sheet name. If \code{NULL} (default), either \code{"grid (wide format)"} or \code{"grid (long format)"}.} } \value{ -Invisibly returns the name of the file. +Invisibly returns file path. } \description{ -\code{saveAsExcel} will save the grid as a Microsoft Excel file -(\code{.xlsx}). +\code{saveAsExcel} will save the grid as a Microsoft Excel file (\code{.xlsx}). } \examples{ +# save grid in wide format (default) +file <- tempfile(fileext = ".xlsx") +saveAsExcel(boeker, file) \dontrun{ - -x <- randomGrid(options = 0) -saveAsExcel(x, "grid.xlsx") +browseURL(file) # open file, requires Excel, may not work on all system } +# save grid in log format +file <- tempfile(fileext = ".xlsx") +saveAsExcel(boeker, file, format = "long") +\dontrun{ +browseURL(file) +} } \seealso{ \code{\link[=importExcel]{importExcel()}} From 72d355f659b4fa4c16b47c25090949a776448429 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Sun, 6 Jul 2025 16:49:35 +0200 Subject: [PATCH 15/28] add `importDataframe()`, refactor `importExcel()` (#61, #65) * `importDataframe` converts a dataframe into a repgrid. Three different formats can be read in. See the sample dataframes `df_element_columns`, `df_construct_columns`, and `df_long` (#61) * `importExcel` now also understands the long format (#65) --- DESCRIPTION | 2 +- NAMESPACE | 5 +- NEWS.md | 7 +- R/data-openrepgrid.r | 137 ++++++++- R/export.r | 21 +- R/import.r | 417 ++++++++++++++++++---------- R/openrepgrid.r | 6 - R/preferred_poles.R | 1 + data/df_construct_columns.RData | Bin 0 -> 240 bytes data/df_element_columns.RData | Bin 0 -> 248 bytes data/df_long.RData | Bin 0 -> 352 bytes inst/examples/example-importExcel.R | 11 + inst/extdata/grid_01.xlsx | Bin 9346 -> 15236 bytes inst/extdata/grid_02.xlsx | Bin 11472 -> 9114 bytes man/OpenRepGrid-overview.Rd | 6 - man/df_construct_columns.Rd | 35 +++ man/df_element_columns.Rd | 34 +++ man/df_long.Rd | 37 +++ man/grid_to_df_long.Rd | 15 + man/grid_to_df_wide.Rd | 15 + man/importDataframe.Rd | 110 ++++++++ man/importExcel.Rd | 105 +++---- man/importExcelInternal.Rd | 27 -- man/importGridcor.Rd | 16 +- man/importGridstat.Rd | 10 +- man/importGridsuite.Rd | 12 +- man/importScivesco.Rd | 10 +- man/importTxt.Rd | 14 +- man/importTxtInternal.Rd | 92 ------ man/roxygen/meta.R | 2 +- vignettes/web/datasets.Rmd | 2 + 31 files changed, 783 insertions(+), 366 deletions(-) create mode 100644 data/df_construct_columns.RData create mode 100644 data/df_element_columns.RData create mode 100644 data/df_long.RData create mode 100644 inst/examples/example-importExcel.R create mode 100644 man/df_construct_columns.Rd create mode 100644 man/df_element_columns.Rd create mode 100644 man/df_long.Rd create mode 100644 man/grid_to_df_long.Rd create mode 100644 man/grid_to_df_wide.Rd create mode 100644 man/importDataframe.Rd delete mode 100644 man/importExcelInternal.Rd delete mode 100644 man/importTxtInternal.Rd diff --git a/DESCRIPTION b/DESCRIPTION index a2883a0..394f70d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9008 +Version: 0.1.18.9009 Date: 2025-07-05 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/NAMESPACE b/NAMESPACE index 563e040..9ab2eae 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -99,13 +99,15 @@ export(getNoOfElements) export(getRatingLayer) export(getScale) export(getScaleMidpoint) +export(grid_to_df_long) +export(grid_to_df_wide) export(gridlist) export(grids_bootstrap) export(grids_leave_n_out) export(grids_perturbate) export(home) +export(importDataframe) export(importExcel) -export(importExcelInternal) export(importGridcor) export(importGridcorInternal) export(importGridstat) @@ -115,7 +117,6 @@ export(importGridsuiteInternal) export(importScivesco) export(importScivescoInternal) export(importTxt) -export(importTxtInternal) export(indexBias) export(indexBieri) export(indexConflict1) diff --git a/NEWS.md b/NEWS.md index d547d0f..4f02a67 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,10 @@ # OpenRepGrid 0.1.18 (dev version) -* `saveAsExcel` now supports output in wide and long format. The output is also formatted now (#64). -* `bertinCluster`: now restores the original `par()` settings after changing the plot layout (#63). +* `importExcel` now also understands the long format (#65) +* `importDataframe` converts a dataframe into a repgrid. Three different formats can be read in. See the sample + dataframes `df_element_columns`, `df_construct_columns`, and `df_long` (#61) +* `saveAsExcel` now supports output in wide and long format. The output is also formatted now (#64) +* `bertinCluster`: now restores the original `par()` settings after changing the plot layout (#63) * `importTxt` reads preferred poles from section `PREFERRED`, `importExcel` reads rightmost column `preferred_poles` (#57) * `preferredPoles` sets the preferred construct poles, `preferredPolesByIdeal` sets the preferred pole bases on the ideal elements ratings, `alignByPreferredPole` aligns constructs by pole preference (#57) diff --git a/R/data-openrepgrid.r b/R/data-openrepgrid.r index 8974073..898e26e 100644 --- a/R/data-openrepgrid.r +++ b/R/data-openrepgrid.r @@ -4,8 +4,10 @@ # # ////////////////////////////////////////////////////////////////////////////// +#_____________ ---- +# REPGRID ---- -# Bell (2010) ---- +## Bell (2010) ---- #' Grid data from Bell (2010). #' @@ -54,7 +56,7 @@ NULL # save("bell2010", file="../data/bell2010.RData") -# Bell and McGorry (1992) ---- +## Bell and McGorry (1992) ---- #' Grid data from Bell and McGorry (1992). #' @@ -112,7 +114,7 @@ NULL # save("bellmcgorry1992", file="../data/bellmcgorry1992.RData") -# Boeker (1996) ---- +## Boeker (1996) ---- #' Grid data from Boeker (1996). #' @@ -171,7 +173,7 @@ NULL # saveAsExcel(boeker, "inst/extdata/boeker.xlsx") -# Fransella, Bell & Bannister (2003) ---- +## Fransella, Bell & Bannister (2003) ---- #' Grid data from Fransella, Bell and Bannister (2003). #' @@ -211,7 +213,7 @@ NULL # save("fbb2003", file="../data/fbb2003.RData") -# Feixas and Saul (2004) ---- +## Feixas and Saul (2004) ---- #' Grid data from Feixas and Saul (2004). #' @@ -277,7 +279,7 @@ NULL -# Leach et al. (2001) ---- +## Leach et al. (2001) ---- #' Pre- and post therapy dataset from Leach et al. (2001). #' @@ -368,7 +370,7 @@ NULL -# Mackay (1992) ---- +## Mackay (1992) ---- #' Grid data from Mackay (1992). #' @@ -405,7 +407,7 @@ NULL # save("mackay1992", file="../data/mackay1992.RData") -# Raeithel (1998) ---- +## Raeithel (1998) ---- #' Grid data from Raeithel (1998). #' @@ -457,7 +459,7 @@ NULL -# Slater (1977a) ---- +## Slater (1977a) ---- #' Drug addict's grid data set from Slater (1977, p. 32). #' @@ -509,7 +511,7 @@ NULL # save("slater1977a", file="../data/slater1977a.RData") -# Slater (1977b) ---- +## Slater (1977b) ---- #' Grid data from Slater (1977). #' @@ -555,3 +557,118 @@ NULL # slater1977b <- makeRepgrid(args) # slater1977b <- setScale(slater1977b, 1, 10) # save("slater1977b", file="../data/slater1977b.RData") + + +#_____________ ---- +# DATAFRAME ---- + +## df_element_columns ---- + +#' Sample dataframe with grid data (elements are columns) +#' +#' This dataframe can be converted into a `repgrid` object via [importDataframe()]. The dataframe column names are the +#' minimum of the rating scale (`1`), the element names (`element_1` to `element_4`), the maximum of the rating scale +#' (`5`), and optionally a column indicating the `preferred` pole. Each row contains the constructs' entries (left +#' pole, ratings, right pole, preferred pole). The preferred pole must be one of `left`, `right`, `none`, `NA` (see +#' [preferredPoles()]). See sample data [df_element_columns]. +#' +#' \tabular{lccccrr}{ +#' `1` \tab `element_1` \tab `element_2` \tab `element_3` \tab `element_4` \tab `5` \tab `preferred` \cr +#' `left_pole_1` \tab `1` \tab `5` \tab `3` \tab `4` \tab `right_pole_1` \tab `left` \cr +#' `left_pole_2` \tab `3` \tab `1` \tab `1` \tab `3` \tab `right_pole_2` \tab `right` \cr +#' `left_pole_3` \tab `4` \tab `2` \tab `5` \tab `1` \tab `right_pole_3` \tab `none` \cr +#' } +#' @name df_element_columns +#' @family grid_dataframe +#' @docType data +#' @seealso [importDataframe()] +#' @keywords data +#' @examples +#' df_element_columns +#' importDataframe(df_element_columns) +NULL + +# # dataframe with columns as elements +# file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") +# x <- importExcel(file) +# x <- x[1:3, 1:4] # smaller version +# df_element_columns <- grid_to_wide_format(x) +# save("df_element_columns", file="data/df_element_columns.RData") +# rg2 <- importDataframe(df_element_columns) + + +## df_construct_columns ---- + +#' Sample dataframe with grid data (constructs are columns) +#' +#' This dataframe can be converted into a `repgrid` object via [importDataframe()]. The columns names are `elements` +#' followed by the constructs (`left_pole_1:right_pole_1` to `left_pole_3:right_pole_3`). The poles are separated by a +#' colon by default (change via arg `pole_sep`). The rows contain the elements' entries (element name and ratings). The +#' min and max of the rating scale should be passed explicitly via the args `rmin` and `rmax`. See sample data +#' [df_construct_columns]. +#' +#' \tabular{lrrrr}{ +#' `elements` \tab `left_pole_1:right_pole_1` \tab `left_pole_2:right_pole_2` \tab `left_pole_3:right_pole_3` \cr +#' `element_1` \tab `5` \tab `3` \tab `2` \cr +#' `element_2` \tab `3` \tab `3` \tab `4` \cr +#' `element_3` \tab `1` \tab `5` \tab `2` \cr +#' `element_4` \tab `4` \tab `3` \tab `3` \cr +#' } +#' @name df_construct_columns +#' @family grid_dataframe +#' @seealso [importDataframe()] +#' @docType data +#' @keywords data +#' @examples +#' df_construct_columns +#' importDataframe(df_construct_columns, format = "construct_columns", rmin =1, rmax = 5) +NULL + +# # dataframe with columns as constructs +# file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") +# x <- importExcel(file) +# x <- x[1:3, 1:4] # smaller version +# df_construct_columns <- grid_to_long_format(x) %>% +# mutate(construct = paste0(left_pole, ":", right_pole)) %>% +# pivot_wider(id_cols = "element", names_from = "construct", values_from = "rating") +# save("df_construct_columns", file="data/df_construct_columns.RData") +# rg2 <- importDataframe(df_construct_columns, format = "c", rmin = 1, rmax = 5) + + +## df_long ---- + +#' Sample dataframe with grid data (long) +#' +#' This dataframe can be converted into a `repgrid` object via [importDataframe()]. +#' The `long` format has this name because it has few columns and many rows. It is a common format +#' in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +#' value. The format looks like this: +#' +#' \tabular{lllrlrr}{ +#' `element` \tab `left_pole` \tab `right_pole` \tab `rating` \tab `preferred_pole` \tab `rmin` \tab `rmax` \cr +#' `element 1` \tab `left pole 1` \tab `right pole 1` \tab `5` \tab `left` \tab `1` \tab `5` \cr +#' `element_2` \tab `left pole 1` \tab `right pole 1` \tab `3` \tab `left` \tab `1` \tab `5` \cr +#' `element_3` \tab `left pole 1` \tab `right pole 1` \tab `1` \tab `left` \tab `1` \tab `5` \cr +#' } +#' +#' The columns `element`, `left_pole`, `right_pole`, and `rating` are mandatory, the columns `preferred_pole`, `rmin`, +#' and `rmax` are optional. `rmin` and `rmax` contain the min and max of the rating scale. Alternatively, you may +#' pass `rmin` and `rmax` as arguments in the function call. +#' +#' @name df_long +#' @family grid_dataframe +#' @seealso [importDataframe()] +#' @docType data +#' @keywords data +#' @examples +#' df_long +#' importDataframe(df_long, format = "long") +NULL + +# # # dataframe with columns as constructs +# file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") +# x <- importExcel(file) +# x <- x[1:3, 1:4] # smaller version +# df_long <- grid_to_long_format(x) +# save("df_long", file="data/df_long.RData") +# rg2 <- importDataframe(df_long, format = "long") diff --git a/R/export.r b/R/export.r index db5875f..7a98f9f 100644 --- a/R/export.r +++ b/R/export.r @@ -207,7 +207,7 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { format <- match.arg(tolower(format), c("wide", "long")) if (format == "wide") { - df <- grid_to_wide_format(x) + df <- grid_to_df_wide(x) sheet <- sheet %||% "grid (wide format)" jj_rows <- seq_len(nrow(df) + 1) jj_elements <- seq_len(ncol(x)) + 1 @@ -232,7 +232,7 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { openxlsx::setColWidths(wb, sheet, cols = c(j_left_pole, j_right_pole, j_preferred), widths = c(20, 20, 13)) openxlsx::saveWorkbook(wb, file, overwrite = TRUE) } else { - df <- grid_to_long_format(x) + df <- grid_to_df_long(x) sheet <- sheet %||% "grid (long format)" jj_rows <- seq_len(nrow(df) + 1) jj_cols <- seq_len(ncol(df)) @@ -260,7 +260,13 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { } -grid_to_wide_format <- function(x) { + +#' Export a grid to dataframe with wide format +#' @param x A `repgrid` object. +#' @export +#' @keywords internal +grid_to_df_wide <- function(x) { + stop_if_not_is_repgrid(x) enames <- elements(x) cnames <- constructs(x) ratings <- ratings(x, names = FALSE) @@ -273,9 +279,14 @@ grid_to_wide_format <- function(x) { } -grid_to_long_format <- function(x) { +#' Export a grid to dataframe with long format +#' @param x A `repgrid` object. +#' @export +#' @keywords internal +grid_to_df_long <- function(x) { + stop_if_not_is_repgrid(x) element <- left_pole <- right_pole <- preferred_pole <- NULL # register for R CMD CHECK - df <- grid_to_wide_format(x) + df <- grid_to_df_wide(x) names(df)[c(1L, ncol(x) + 2)] <- c("left_pole", "right_pole") df_long <- df %>% tidyr::pivot_longer(-c(left_pole, right_pole, preferred_pole), names_to = "element", values_to = "rating") diff --git a/R/import.r b/R/import.r index be66d3f..29c559d 100644 --- a/R/import.r +++ b/R/import.r @@ -1,4 +1,6 @@ -################### import repgrid data from other (grid) programs ############ +# _______________---- +# IMPORT GRID DATA ----------- + # # programs currently supported: # @@ -68,7 +70,7 @@ convertImportObjectToRepGridObject <- function(import) { } -############################ GRIDSTAT ######################################### +## GRIDSTAT ---- # gridstat output has the following form. # 1) first line: some description elements. @@ -390,11 +392,8 @@ multigridFileToSinglegridFiles <- function(file) { #' names are assigned to elements and constructs. #' #' @export +#' @family import #' @references Bell, R. C. (1998) GRIDSTAT: A program for analyzing the data of a repertory grid. Melbourne: Author. -#' -#' @seealso [importGridcor()], [importGridstat()], [importScivesco()], [importGridsuite()], [importTxt()], -#' [importExcel()] -#' #' @examples \dontrun{ #' #' # supposing that the data file gridstat.dat is in the current working directory @@ -430,7 +429,7 @@ importGridstat <- function(file, dir = NULL, min = NULL, max = NULL) { -############################# GRIDCOR ######################################### +## GRIDCOR ------------------------------------------------------------------------------------ # gridcor outpout has the following form: # "As you can see in this sample file, the first line contains the number of constructs (10), @@ -609,17 +608,11 @@ importGridcorInternal <- function(file, dir = NULL) { #' #' Also note that both Gridcor and Gridstat data files do have the same suffix `.dat`. Make sure not to mix them up. #' @export +#' @family import #' @references Feixas, G., & Cornejo, J. M. (2002). GRIDCOR: Correspondence Analysis #' for Grid Data (version 4.0). Barcelona: Centro de Terapia Cognitiva. #' Retrieved from . #' -#' @seealso [importGridcor()], -#' [importGridstat()], -#' [importScivesco()], -#' [importGridsuite()], -#' [importTxt()], -#' [importExcel()] -#' #' @examples \dontrun{ #' #' # supposing that the data file gridcor.dat is in the current directory @@ -647,9 +640,7 @@ importGridcor <- function(file, dir = NULL) { } - - -############################# GRIDSUITE ####################################### +## GRIDSUITE ------------------------------------------------------------------------------------ # # On www.gridsuite.de there are example files and XSD schemes available. @@ -780,9 +771,7 @@ importGridsuiteInternal <- function(file, dir = NULL) { #' current mechanism will cause false assignments. #' #' @export -#' @seealso [importGridcor()], [importGridstat()], [importScivesco()], [importGridsuite()], [importTxt()], -#' [importExcel()] -#' +#' @family import #' @examples \dontrun{ #' #' # supposing that the data file gridsuite.xml is in the current directory @@ -810,7 +799,7 @@ importGridsuite <- function(file, dir = NULL) { } -############################# sci:vesco ####################################### +## sci:vesco ------------------------------------------------------------------------------------ # scivesco saves single grids in .scires files which have an XML structure. # Note: not all nodes are imported by importScivesco() @@ -1110,10 +1099,7 @@ convertScivescoImportObjectToRepGridObject <- function(import) { #' @export #' @references Menzel, F., Rosenberger, M., Buve, J. (2007). Emotionale, intuitive und #' rationale Konstrukte verstehen. *Personalfuehrung, 4*(7), 91-99. -#' -#' @seealso [importGridcor()], [importGridstat()], [importScivesco()], [importGridsuite()], [importTxt()], -#' [importExcel()] -#' +#' @family import #' @examples \dontrun{ #' #' # supposing that the data file scivesco.scires is in the current directory @@ -1141,7 +1127,8 @@ importScivesco <- function(file, dir = NULL) { } -############################# IMPORT .TXT ####################################### +## .txt ------------------------------------------------------------------------------------ + #' ImportTxtInternal is the parser for importTxt. #' @@ -1205,8 +1192,7 @@ importScivesco <- function(file, dir = NULL) { #' for maximum rating value in grid. #' @return List of relevant data. #' -#' @export -#' @keywords internal +#' @noRd #' @examples \dontrun{ #' #' # supposing that the data file sample.txt is in the current directory @@ -1397,22 +1383,21 @@ importTxtInternal <- function(file, dir = NULL, min = NULL, max = NULL) { #' thus strongly recommended to set the scale range correctly. #' #' @export -#' @seealso [importGridcor()], [importGridstat()], [importScivesco()], [importGridsuite()], [importTxt()], -#' [importExcel()] +#' @family import #' @examples #' # Import a .txt file delivered along with the package #' file <- system.file("extdata", "grid_01.txt", package = "OpenRepGrid") #' rg <- importTxt(file) #' -#' \dontrun{ #' # To see the structure of the file, try opening it as follows. #' # (may not work on all systems) -#' file.show(file) +#' \dontrun{ file.show(file) #' } #' #' # Import more than one .txt file #' files <- system.file("extdata", c("grid_01.txt", "grid_02.txt"), package = "OpenRepGrid") #' rgs <- importTxt(files) +#' importTxt <- function(file, dir = NULL, min = NULL, max = NULL) { imps <- lapply(as.list(file), importTxtInternal, # make import objects for each .txt file dir = dir, min = min, max = max @@ -1426,164 +1411,298 @@ importTxt <- function(file, dir = NULL, min = NULL, max = NULL) { } -############################# IMPORT EXCEL #################################### +## DATAFRAME ------------------------------------------------------------------------------------ -#' workhorse function (parser) for importExcel. -#' -#' @inheritParams importExcel -#' @export -#' @keywords internal -importExcelInternal <- function(file, dir = NULL, sheet = 1, - min = NULL, max = NULL) { - if (!is.null(dir)) { - file <- paste(dir, file, sep = "/", collapse = "") +#' Convert dataframe to repgrid object (internal) +#' @param x A dataframe with predefined format. +#' @param rmin,rmax Min and max of the rating scale. +#' @return A reogrid object +#' @noRd +df_wide_to_grid <- function(x, rmin = NULL, rmax = NULL ) { + if (!is.data.frame(x)) { + stop("'x' must be a dataframe. Got '", class(x)[1], "' instead.") } + nms <- names(x) <- trimws(names(x)) + col_last <- tail(nms, 1) + # last_col_numeric <- grepl("^[0-9]+$", col_last) + last_col_has_preferred_poles <- grepl("^preferred.*", tolower(col_last)) + nc <- nrow(x) # number of constructs + ne <- ncol(x) - 2L - last_col_has_preferred_poles # number of elements - # read in Excel file - x <- openxlsx::read.xlsx(file, sheet = sheet, colNames = FALSE) # read .xlxs or .xls file + col_left_poles <- 1 + col_right_poles <- ne + 2L + cols_elements <- seq_len(ne) + 1L + rows_ratings <- seq_len(nc) - # remove NA lines if too many rows in Excel - na.rows <- apply(x, 1, function(x) all(is.na(unlist(x)))) - x <- x[!na.rows, ] + ratings <- x[rows_ratings, cols_elements] %>% as.matrix() %>% as.numeric() + if (any(is.na(ratings))) { + stop("\nNA ratings are not allowed.", call. = FALSE) + } - last_col_value <- str_trim(x[1L, ncol(x)]) - last_col_numeric <- last_col_value %>% - str_trim() %>% - str_detect("^[0-9]+$") - last_col_has_preferred_poles <- tolower(last_col_value) %>% str_detect("^preferred.*") + # determine rating range + rmin <- rmin %||% suppressWarnings(as.numeric(trimws(nms[col_left_poles]))) # supress NA conversion, NA handled below + rmax <- rmax %||% suppressWarnings(as.numeric(trimws(nms[col_right_poles]))) - nc <- nrow(x) - 1L # number of constructs - ne <- ncol(x) - 2L - last_col_has_preferred_poles # number of elements + # if unknown range, infer from data with warning + if (identical(rmin, numeric(0)) || is.na(rmin) || identical(rmax, numeric(0))|| is.na(rmax) ) { + warning("The range of the rating scale was not supplied via args `rmin` and `rmax`.", + "\nI will set the min and max rating as scale range. This may be incorrect!", + "\nSee `?importExcel` for more information", + call. = FALSE + ) + rmin <- min(ratings, na.rm = TRUE) # infer rating range + rmax <- max(ratings, na.rm = TRUE) + } - elements_col_start <- 2L - elements_col_end <- ncol(x) - 1L - last_col_has_preferred_poles - cols_elements <- elements_col_start:elements_col_end + # easier than building from scratch, as makeEmptyRepgrid() appears not suited here + rg <- randomGrid(ne = ne, nc = nc, range = c(rmin, rmax), options = 0) + ratings(rg) <- ratings + elements(rg) <- nms[cols_elements] + leftpoles(rg) <- x[[col_left_poles]] + rightpoles(rg) <- x[[col_right_poles]] + preferredPoles(rg) <- x[["preferred_pole"]] # if not present => NULL => NA + rg +} - rows_ratings <- seq_len(nc) + 1L - l <- list() +df_long_to_wide <- function(df, rmin = NULL, rmax = NULL) { + left_pole <- preferred_pole <- right_pole <- NULL # register vars for R CMD CHECK + if (!is.data.frame(df)) { + stop("'df' must be a dataframe. Got '", class(df)[1], "' instead.") + } + cols_required <- c("element", "left_pole", "right_pole", "rating") + cols_optional <- c("preferred_pole", "rmin", "rmax") + nms <- names(df) + cols_missing <- cols_required[!cols_required %in% nms] + if (length(cols_missing) > 0) { + stop("\nMissing columns: ", paste(shQuote(cols_missing), collapse = ", "), + "\nSee `importDataframe()` for long format requirements.", call. = FALSE) + } - # read elements - l$elements <- as.list(as.character(unlist(x[1, cols_elements]))) # list of element names + rmin <- df[["rmin"]] %>% unique() + rmax <- df[["rmax"]] %>% unique() - # read constructs and trim blanks - l$emergentPoles <- as.list(as.character(x[rows_ratings, 1L])) - l$contrastPoles <- as.list(as.character(x[rows_ratings, ne + 2L])) + # convert to wide, simple approach, as we already have an importer for a wide grid + df_wide <- df %>% + tidyr::pivot_wider(id_cols = c("left_pole", "right_pole"), names_from = "element", values_from = "rating") %>% + dplyr::relocate(right_pole, .after = last_col()) + df_pref <- df %>% dplyr::count(left_pole, preferred_pole) %>% select(-n) + df_wide <- df_wide %>% left_join(df_pref, by = join_by(left_pole)) - if (last_col_has_preferred_poles) { - l$preferredPoles <- as.list(as.character(x[rows_ratings, ncol(x)])) + if (!is.null(rmin) && !is.null(rmax)) { + jj_poles <- c(1L, ncol(df_wide) - 1) + names(df_wide)[jj_poles] <- c(rmin, rmax) } - # read ratings and convert to numeric - ratings <- x[rows_ratings, cols_elements] - ratings <- sapply(ratings, function(x) as.numeric(as.character(x))) # convert to numerics - l$ratings <- split(ratings, 1L:nrow(ratings)) # convert df to list row-wise + df_wide +} - # read range info if available - rmin <- as.numeric(as.vector(x[1L, 1L])) - rmax <- as.numeric(as.vector(x[1L, ne + 2L])) - # if not availabe infer range data and issue warning - if (identical(rmin, numeric(0)) || identical(rmax, numeric(0))) { - warning("the minimum and/or the maximum value of the rating scale have not been set explicitly.", - "The scale range was thus inferred by scanning the available ratings and may be wrong.", - "See ?importExcel for more information", - call. = FALSE - ) - rmin <- min(ratings, na.rm = TRUE) # infer rating range - rmax <- max(ratings, na.rm = TRUE) +#' Transpose grid dataframe +#' Covers the case if elements come in rows instead of columns. +#' @param x A dataframe. Required format: Elements in first column, constructs as columns names. +#' @param pole_sep Seperator for construct poles (default is a colon). +#' @noRd +#' @return A dataframe in standard dataframe format. +#' +df_construct_cols_to_wide <- function(x, pole_sep = ":") { + x_raw <- x + if (!all(grepl("[a-zA-Z]", x_raw[[1]]))) { + warning("The first column must contain the element names") } + constructs <- names(x_raw)[-1] + x <- as.data.frame(t(x_raw)) + rownames(x) <- NULL + names(x) <- x[1L, ] + x <- x[-1L, ] # elements only + + list_poles <- stringr::str_split(constructs, pole_sep) # split left poles: right pole + list_poles <- lapply(list_poles, stringr::str_trim) + list_poles <- lapply(list_poles, rev) # put right poles first for easier selection + right_poles <- sapply(list_poles, "[", 1L) # by default right pole + left_poles <- sapply(list_poles, "[", 2L) # if exist, else NA + cbind(left = left_poles, x, right = right_poles) +} - # overwrite scale range if given in arguments - if (!is.null(min)) { - rmin <- min + +#' Convert a dataframe into a repgrid object. +#' +#' There are three different dataframe formats from which a `repgrid` object can be created: +#' Columns are a) `element_columns`, b) `construct_columns`, c) `long`. +#' Three corresponding sample dataframes, ([df_element_columns], [df_construct_columns], and [df_long]) are included +#' in the package (see examples). See Detail section below for more info. +#' +#' +#' @section Format `element_columns`: +#' +#' In this format, each element has a separate column, and each row contains the ratings for one construct. +#' It is a common way to represent grid data and looks like this. +#' +#' \tabular{lccccrr}{ +#' `1` \tab `element_1` \tab `element_2` \tab `element_3` \tab `element_4` \tab `5` \tab `preferred` \cr +#' `left_pole_1` \tab `1` \tab `5` \tab `3` \tab `4` \tab `right_pole_1` \tab `left` \cr +#' `left_pole_2` \tab `3` \tab `1` \tab `1` \tab `3` \tab `right_pole_2` \tab `right` \cr +#' `left_pole_3` \tab `4` \tab `2` \tab `5` \tab `1` \tab `right_pole_3` \tab `NA` \cr +#' } +#' +#' The columns names contains the minimum of the rating scale (`1`), the names of the elements (`element_1` to +#' `element_4`), the maximum of the rating scale (`5`), and optionally the column `preferred`, indicating the preferred +#' pole. Each row contains the constructs entries (left pole, ratings, right pole, preferred pole). The preferred pole +#' must be one of `left`, `right`, `none`, `NA` (see [preferredPoles()]). See sample dataframe [df_element_columns]. +#' +#' +#' @section Format `construct_columns`: +#' +#' In this format, each construct has a separate column, and each row contains represents element. This format often +#' results when summarising data (see examples). It looks like this: +#' +#' The first column is named `elements` followed by the constructs. The construct poles are separated by a colon by +#' default (see arg `pole_sep`). The rows below contain the elements' entries (element name, ratings). The min and max +#' of the rating scale should be passed explicitly via the args `rmin` and `rmax`. See sample dataframe +#' [df_construct_columns]. +#' +#' \tabular{lrrr}{ +#' `elements` \tab `left_pole_1:right_pole_1` \tab `left_pole_2:right_pole_2` \tab `left_pole_3:right_pole_3` \cr +#' `element_1` \tab `1` \tab `5` \tab `3` \cr +#' `element_2` \tab `3` \tab `1` \tab `1` \cr +#' `element_3` \tab `4` \tab `2` \tab `5` \cr +#' } +#' +#' +#' @section Format `long`: +#' +#' The `long` format gets its name from the fact, that it has less columns, but many more rows. It is a common format +#' in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +#' value. The format looks like this: +#' +#' \tabular{lllrlrr}{ +#' `element` \tab `left_pole` \tab `right_pole` \tab `rating` \tab `preferred_pole` \tab `rmin` \tab `rmax` \cr +#' `element 1` \tab `left pole 1` \tab `right pole 1` \tab `1` \tab `left` \tab `1` \tab `5` \cr +#' `element_2` \tab `left pole 1` \tab `right pole 1` \tab `5` \tab `left` \tab `1` \tab `5` \cr +#' `element_3` \tab `left pole 1` \tab `right pole 1` \tab `4` \tab `left` \tab `1` \tab `5` \cr +#' } +#' +#' The columns `element`, `left_pole`, `right_pole`, and `rating` are mandatory, the columns `preferred_pole`, `rmin`, +#' and `rmax` are optional. `rmin` and `rmax` contain the min and max of the rating scale. Alternatively, you may +#' pass `rmin` and `rmax` as arguments in the function call. See sample dataframe [df_long]. +#' +#' +#' @param x A dataframe. See Detail section and examples for required format. +#' @param format One of `element_columns` (default), `construct_columns`, or `long`. See corresponding sections below. +#' @param rmin,rmax Min and max of rating scale. +#' @param pole_sep Character(s) to seperate the constructs poles (defaults to a colon) for format `construct_columns`. +#' Without a separator, constructs are used as right poles, all left poles will be `NA`. +#' @return A `repgrid`` object. +#' @family import +#' @export +#' @examples +#' # dataframe with elements as columns (preferred way) +#' importDataframe(df_element_columns) +#' +#' # dataframe with constructs as columns +#' importDataframe(df_construct_columns, format = "construct_columns", rmin = 1, rmax = 5) +#' +#' # dataframe with long format +#' importDataframe(df_long, format = "long", rmin = 1, rmax = 5) +importDataframe <- function(x, format = "element_columns", rmin = NULL, rmax = NULL, pole_sep = ":") { + if (!is.data.frame(x)) { + stop("'x' must be a dataframe. Got <", class(x)[1], "> instead.") } - if (!is.null(max)) { - rmax <- max + format <- match.arg(tolower(format), choices = c("element_columns", "construct_columns", "long")) + if (format == "construct_columns") { + x <- df_construct_cols_to_wide(x, pole_sep = pole_sep) + } else if (format == "long") { + x <- df_long_to_wide(x, rmin = rmin, rmax = rmax) } - - l$noConstructs <- nc # no of constructs - l$noElements <- ne # no of elements - l$minValue <- rmin # minimum value for Likert scale - l$maxValue <- rmax # maximum value for Likert scale - l + df_wide_to_grid(x, rmin = rmin, rmax = rmax) } +## EXCEL ------------------------------------------------------------------------------------ + #' Import grid data from an Excel file. #' -#' You can define a grid using Microsoft Excel and by saving it as a -#' `.xlsx` file. The `.xlsx` file has to be in a specified fixed -#' format (see section Details). +#' You can define a grid in a Microsoft Excel file (suffix `.xlsx`). The file must have one of +#' two formats (`wide` or `long`, see format sections below). #' -#' Excel file structure: The first row contains the minimum of the rating scale, -#' the names of the elements and the maximum of the rating scale. Below every -#' row contains the left construct pole, the ratings and the right construct -#' pole. +#' @section Format `wide`: #' -#' \tabular{lccccr}{ -#' `1` \tab `E1` \tab `E2` \tab `E3` \tab `E4` \tab `5` \cr -#' `left pole 1` \tab `1` \tab `5` \tab `3` \tab `4` \tab `right pole 1` \cr -#' `left pole 2` \tab `3` \tab `1` \tab `1` \tab `3` \tab `right pole 2` \cr -#' `left pole 3` \tab `4` \tab `2` \tab `5` \tab `1` \tab `right pole 3` \cr -#' } +#' In the `wide` format, each element has a separate column, and each row contains the ratzings for one construct. +#' It is a common way to represent grid data and looks like this: #' -#' Note that the maximum and minimum value has to be defined using the -#' `min` and `max` arguments if no values are supplied at the -#' beginning and end of the first row. Otherwise the scaling range is inferred -#' from the available data and a warning is issued as the range may be -#' erroneous. This may effect other functions that depend on knowing the correct -#' range and it is thus strongly recommended to set the scale range correctly. +#' \tabular{lccccrr}{ +#' `1` \tab `element_1` \tab `element_2` \tab `element_3` \tab `element_4` \tab `5` \tab `preferred` \cr +#' `left_pole_1` \tab `1` \tab `5` \tab `3` \tab `4` \tab `right_pole_1` \tab `left` \cr +#' `left_pole_2` \tab `3` \tab `1` \tab `1` \tab `3` \tab `right_pole_2` \tab `right` \cr +#' `left_pole_3` \tab `4` \tab `2` \tab `5` \tab `1` \tab `right_pole_3` \tab `NA` \cr +#' } #' -#' @param file A vector of filenames including the full path if file is not in current working -#' directory. The file suffix has to be `.xlsx` (used since Excel 2007). -#' @param dir Alternative way to supply the directory where the file is located -#' (default `NULL`). -#' @param sheet Name or index of Excel sheet containing the grid. -#' @param min Optional argument (`numeric`, default `NULL`) -#' for minimum rating value in grid. -#' @param max Optional argument (`numeric`, default `NULL`) -#' for maximum rating value in grid. -#' @return A single `repgrid` object in case one file and -#' a list of `repgrid` objects in case multiple files are imported. -#' @export -#' @seealso [importGridcor()], -#' [importGridstat()], -#' [importScivesco()], -#' [importGridsuite()], -#' [importTxt()] +#' The header row contains the minimum of the rating scale (`1`), the names of the elements (`element_1` to `element_4`), +#' the maximum of the rating scale (`5`), and optionally the column `preferred`, indicating the preferred pole. +#' Each row contains the constructs entries (left pole, ratings, right pole, preferred pole). The preferred pole +#' must be one of `left`, `right`, `none`, `NA` (see [preferredPoles()]). #' -#' @examples \dontrun{ #' -#' # Open Excel file delivered along with the package -#' file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") -#' rg <- importExcel(file) +#' @section Format `long`: #' -#' # To see the structure of the Excel file try to open it as follows. -#' # Requires Excel to be installed. -#' system2("open", file) +#' The `long` format has this name because it has few columns and many rows. It is a common format +#' in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +#' value. The format looks like this: #' -#' # Import more than one Excel file -#' files <- system.file("extdata", c("grid_01.xlsx", "grid_02.xlsx"), package = "OpenRepGrid") -#' rg <- importExcel(files) +#' \tabular{lllrlrr}{ +#' `element` \tab `left_pole` \tab `right_pole` \tab `rating` \tab `preferred_pole` \tab `rmin` \tab `rmax` \cr +#' `element 1` \tab `left pole 1` \tab `right pole 1` \tab `1` \tab `left` \tab `1` \tab `5` \cr +#' `element_2` \tab `left pole 1` \tab `right pole 1` \tab `5` \tab `left` \tab `1` \tab `5` \cr +#' `element_3` \tab `left pole 1` \tab `right pole 1` \tab `4` \tab `left` \tab `1` \tab `5` \cr #' } #' -importExcel <- function(file, dir = NULL, sheet = 1, min = NULL, max = NULL) { - imps <- lapply(as.list(file), importExcelInternal, # make import objects for each .txt file - dir = dir, sheet = sheet, - min = min, max = max - ) - rgs <- lapply(imps, convertImportObjectToRepGridObject) # make repgrid object from import object - if (length(file) == 1) { - return(rgs[[1]]) # return a single repgrid opbject if a single file is prompted +#' The columns `element`, `left_pole`, `right_pole`, and `rating` are mandatory, the columns `preferred_pole`, `rmin`, +#' and `rmax` are optional. `rmin` and `rmax` contain the min and max of the rating scale. Alternatively, you may +#' pass `rmin` and `rmax` as arguments in the function call. +#' +#' @param file Path(s) to Excel file(s) (suffix `.xlsx`). +#' @param sheet Name or index of sheet with grid data. +#' @param format Two formats are supported. `wide` (default): each column represents one element, each row represent +#' one constructs. `long`: each row contains one rating value for a element-construct combination. See +#' sections below and examples. +#' @param rmin,rmax Min and max of the rating scale (`numeric`, default `NULL`). +#' @return A single `repgrid` object (one inpput file) or a list of `repgrid` objects (several input files). +#' @export +#' @family import +#' @example inst/examples/example-importExcel.R +#' +importExcel <- function(file, sheet = 1, format = "wide", rmin = NULL, rmax = NULL) { + format <- match.arg(tolower(format), c("wide", "long")) + + rgs <- if (format == "wide") { + lapply(file, import_excel_wide, sheet = sheet, rmin = rmin, rmax = rmax) } else { - return(rgs) # return a list of repgrid objects + lapply(file, import_excel_long, sheet = sheet, rmin = rmin, rmax = rmax) + } + + if (length(rgs) == 1) { + return(rgs[[1]]) # no list, just a single repgrid object + } else { + return(rgs) # list of repgrid objects } } +import_excel_wide <- function(file, sheet = 1,rmin = NULL, rmax = NULL) { + x <- openxlsx::read.xlsx(file, sheet = sheet, colNames = FALSE) # colNames = FALSE as spaces are treated incorrectly + names(x) <- x[1L, ] + x <- x[-1L, ] + importDataframe(x, format = "element_columns", rmin = rmin, rmax = rmax) +} + + +import_excel_long <- function(file, sheet = 1,rmin = NULL, rmax = NULL) { + x <- openxlsx::read.xlsx(file, sheet = sheet, colNames = TRUE) + importDataframe(x, format = "long", rmin = rmin, rmax = rmax) +} + -############################# IMPORTING ################################### +# HELPERS -------------------------------------------------------------------------------- guessDataSource <- function(file) { diff --git a/R/openrepgrid.r b/R/openrepgrid.r index e07d5ea..5d08d78 100644 --- a/R/openrepgrid.r +++ b/R/openrepgrid.r @@ -248,12 +248,6 @@ #' [doubleEntry()] \tab Join the constructs of a grid with the same reversed constructs. \cr #' } #' -#' **Other internal functions** \cr -#' -#' \tabular{ll}{ -#' [importTxtInternal()] \tab \cr -#' } -#' #' @author Current members of the \pkg{OpenRepGrid} development team: Mark Heckmann. #' Everyone who is interested in developing the package is invited to join. #' diff --git a/R/preferred_poles.R b/R/preferred_poles.R index 01ac437..9370d00 100644 --- a/R/preferred_poles.R +++ b/R/preferred_poles.R @@ -28,6 +28,7 @@ preferredPoles <- function(x) { `preferredPoles<-` <- function(x, value) { stop_if_not_is_repgrid(x) nc <- nrow(x) + value <- value %||% NA # replace NULL with NA value <- rep_len(value, length.out = nc) value <- as.character(value) # all NA case value <- match.arg2(value, c("left", "right", "none", "both", NA_character_), several.ok = TRUE) diff --git a/data/df_construct_columns.RData b/data/df_construct_columns.RData new file mode 100644 index 0000000000000000000000000000000000000000..e0dedbe0bad6c6221d8500da10fb62b8903c4389 GIT binary patch literal 240 zcmVqu^LfS5E z%3k-um#tGxuuKore1G|xWdC&%{>cXb2AnfsE<$jRhu!KEfRB(kz`?_Hk!I(lENWdf ziAJQFyr^;C96gRRd#J)pLk-P q$k3&dnGU{7C4+EV-LE%GhJMudqoFVQe)mxS-8=v@z&Au40ssKa`g9cl literal 0 HcmV?d00001 diff --git a/data/df_element_columns.RData b/data/df_element_columns.RData new file mode 100644 index 0000000000000000000000000000000000000000..b10e78642d4f8923a28cd1ea19a125a5200286eb GIT binary patch literal 248 zcmVawgC=mivPDtG|d1IRA;SBjmgkfxGW z_IEF?b*c^QPW+hU<>lq^X0qMvWVj0fzyl#X@O*;ce}8?>*8pNjhXDu(X#dEI6cv`J zn{;2POQ~ymHKUsm)%(-pp&TnLn&@09jFv7HyOd-GgOvr+f|yIB0}?J-I(Cjr^1|-F zWMWQ-BkSfb7r)@Rhv-`EvH#H73teesbM|#sV% y^R&y&gX~pS+aQ(<^Q_4hg`td09+>K9VY5%EhQGA5ZF{Bd*3}&*hD;-E0ssKw#dh!j literal 0 HcmV?d00001 diff --git a/data/df_long.RData b/data/df_long.RData new file mode 100644 index 0000000000000000000000000000000000000000..af591c104621dfc754d3b5d93bc9dff7138e79dd GIT binary patch literal 352 zcmV-m0iXUKiwFP!000001I<<4O2aS|K5bJ+>l}hUz+S+C?F8@iLVN&G*jorN?V zSwSy-WG}p4J^hJWQUs?RvykSTFDL2uB`2qMH?z>6`2gSmAr3e$n&3X%-=19p5E~r} z2zb~J;w0j^m}BTkOPxg#|rh;h!*Fw{@Wm6>TXA*0eJeem^Vd%nH^q`Zq~+3|rW4&3`+G zh+MEA*&b&?JK++<`pGD)17Lp}QN)~U%5V<}8v?~T$ig+@AnW!{5 y!e+nWt1Qb8Gnbw?U8-Di6ocZCM{%MAqNm8lw4jqj;=+w&SbYNXulm&o2LJ#hxSnAE literal 0 HcmV?d00001 diff --git a/inst/examples/example-importExcel.R b/inst/examples/example-importExcel.R new file mode 100644 index 0000000..96cb18c --- /dev/null +++ b/inst/examples/example-importExcel.R @@ -0,0 +1,11 @@ +file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") +rg_1 <- importExcel(file, sheet = "wide") +rg_2 <- importExcel(file, sheet = "long", format = "long") + +# Open Sample file to inspect the two (requires Excel to be installed). +\dontrun{ +browseURL(file) # may not work on all systems } + +# Import more than one Excel file +files <- system.file("extdata", c("grid_01.xlsx", "grid_02.xlsx"), package = "OpenRepGrid") +rgs <- importExcel(files) # returns a list of grids diff --git a/inst/extdata/grid_01.xlsx b/inst/extdata/grid_01.xlsx index 5e1f4ab9846ec24d443b26c101b28542eb658f76..7d0b6899f6311c05192431140afc8d077002d1cc 100644 GIT binary patch delta 10986 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 O1c0X)>uuIQr2hlVeoXfO diff --git a/inst/extdata/grid_02.xlsx b/inst/extdata/grid_02.xlsx index 9be749ebe212e8eb201ffb8ae470a2822e3365da..5229bae62ee0fd9da1a069883b228bb2410a3078 100644 GIT binary patch literal 9114 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 literal 11472 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 ZnvUndq9eolw=)nWzzZ3WWmvww{Xf*Lp-KP% diff --git a/man/OpenRepGrid-overview.Rd b/man/OpenRepGrid-overview.Rd index af0375a..4acff50 100644 --- a/man/OpenRepGrid-overview.Rd +++ b/man/OpenRepGrid-overview.Rd @@ -212,12 +212,6 @@ functions for these purposes. \code{\link[=bindConstructs]{bindConstructs()}} \tab Concatenate the constructs of two grids. \cr \code{\link[=doubleEntry]{doubleEntry()}} \tab Join the constructs of a grid with the same reversed constructs. \cr } - -\strong{Other internal functions} \cr - -\tabular{ll}{ -\code{\link[=importTxtInternal]{importTxtInternal()}} \tab \cr -} } \seealso{ diff --git a/man/df_construct_columns.Rd b/man/df_construct_columns.Rd new file mode 100644 index 0000000..0688c64 --- /dev/null +++ b/man/df_construct_columns.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data-openrepgrid.r +\docType{data} +\name{df_construct_columns} +\alias{df_construct_columns} +\title{Sample dataframe with grid data (constructs are columns)} +\description{ +This dataframe can be converted into a \code{repgrid} object via \code{\link[=importDataframe]{importDataframe()}}. The columns names are \code{elements} +followed by the constructs (\code{left_pole_1:right_pole_1} to \code{left_pole_3:right_pole_3}). The poles are separated by a +colon by default (change via arg \code{pole_sep}). The rows contain the elements' entries (element name and ratings). The +min and max of the rating scale should be passed explicitly via the args \code{rmin} and \code{rmax}. See sample data +\link{df_construct_columns}. +} +\details{ +\tabular{lrrrr}{ +\code{elements} \tab \code{left_pole_1:right_pole_1} \tab \code{left_pole_2:right_pole_2} \tab \code{left_pole_3:right_pole_3} \cr +\code{element_1} \tab \code{5} \tab \code{3} \tab \code{2} \cr +\code{element_2} \tab \code{3} \tab \code{3} \tab \code{4} \cr +\code{element_3} \tab \code{1} \tab \code{5} \tab \code{2} \cr +\code{element_4} \tab \code{4} \tab \code{3} \tab \code{3} \cr +} +} +\examples{ +df_construct_columns +importDataframe(df_construct_columns, format = "construct_columns", rmin =1, rmax = 5) +} +\seealso{ +\code{\link[=importDataframe]{importDataframe()}} + +Other grid dataframes: +\code{\link{df_element_columns}}, +\code{\link{df_long}} +} +\concept{grid_dataframe} +\keyword{data} diff --git a/man/df_element_columns.Rd b/man/df_element_columns.Rd new file mode 100644 index 0000000..9ffb827 --- /dev/null +++ b/man/df_element_columns.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data-openrepgrid.r +\docType{data} +\name{df_element_columns} +\alias{df_element_columns} +\title{Sample dataframe with grid data (elements are columns)} +\description{ +This dataframe can be converted into a \code{repgrid} object via \code{\link[=importDataframe]{importDataframe()}}. The dataframe column names are the +minimum of the rating scale (\code{1}), the element names (\code{element_1} to \code{element_4}), the maximum of the rating scale +(\code{5}), and optionally a column indicating the \code{preferred} pole. Each row contains the constructs' entries (left +pole, ratings, right pole, preferred pole). The preferred pole must be one of \code{left}, \code{right}, \code{none}, \code{NA} (see +\code{\link[=preferredPoles]{preferredPoles()}}). See sample data \link{df_element_columns}. +} +\details{ +\tabular{lccccrr}{ +\code{1} \tab \code{element_1} \tab \code{element_2} \tab \code{element_3} \tab \code{element_4} \tab \code{5} \tab \code{preferred} \cr +\code{left_pole_1} \tab \code{1} \tab \code{5} \tab \code{3} \tab \code{4} \tab \code{right_pole_1} \tab \code{left} \cr +\code{left_pole_2} \tab \code{3} \tab \code{1} \tab \code{1} \tab \code{3} \tab \code{right_pole_2} \tab \code{right} \cr +\code{left_pole_3} \tab \code{4} \tab \code{2} \tab \code{5} \tab \code{1} \tab \code{right_pole_3} \tab \code{none} \cr +} +} +\examples{ +df_element_columns +importDataframe(df_element_columns) +} +\seealso{ +\code{\link[=importDataframe]{importDataframe()}} + +Other grid dataframes: +\code{\link{df_construct_columns}}, +\code{\link{df_long}} +} +\concept{grid_dataframe} +\keyword{data} diff --git a/man/df_long.Rd b/man/df_long.Rd new file mode 100644 index 0000000..12bfcd3 --- /dev/null +++ b/man/df_long.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data-openrepgrid.r +\docType{data} +\name{df_long} +\alias{df_long} +\title{Sample dataframe with grid data (long)} +\description{ +This dataframe can be converted into a \code{repgrid} object via \code{\link[=importDataframe]{importDataframe()}}. +The \code{long} format has this name because it has few columns and many rows. It is a common format +in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +value. The format looks like this: +} +\details{ +\tabular{lllrlrr}{ +\code{element} \tab \code{left_pole} \tab \code{right_pole} \tab \code{rating} \tab \code{preferred_pole} \tab \code{rmin} \tab \code{rmax} \cr +\verb{element 1} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{5} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_2} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{3} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_3} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{1} \tab \code{left} \tab \code{1} \tab \code{5} \cr +} + +The columns \code{element}, \code{left_pole}, \code{right_pole}, and \code{rating} are mandatory, the columns \code{preferred_pole}, \code{rmin}, +and \code{rmax} are optional. \code{rmin} and \code{rmax} contain the min and max of the rating scale. Alternatively, you may +pass \code{rmin} and \code{rmax} as arguments in the function call. +} +\examples{ +df_long +importDataframe(df_long, format = "long") +} +\seealso{ +\code{\link[=importDataframe]{importDataframe()}} + +Other grid dataframes: +\code{\link{df_construct_columns}}, +\code{\link{df_element_columns}} +} +\concept{grid_dataframe} +\keyword{data} diff --git a/man/grid_to_df_long.Rd b/man/grid_to_df_long.Rd new file mode 100644 index 0000000..884d5e3 --- /dev/null +++ b/man/grid_to_df_long.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/export.r +\name{grid_to_df_long} +\alias{grid_to_df_long} +\title{Export a grid to dataframe with long format} +\usage{ +grid_to_df_long(x) +} +\arguments{ +\item{x}{A \code{repgrid} object.} +} +\description{ +Export a grid to dataframe with long format +} +\keyword{internal} diff --git a/man/grid_to_df_wide.Rd b/man/grid_to_df_wide.Rd new file mode 100644 index 0000000..94aa4af --- /dev/null +++ b/man/grid_to_df_wide.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/export.r +\name{grid_to_df_wide} +\alias{grid_to_df_wide} +\title{Export a grid to dataframe with wide format} +\usage{ +grid_to_df_wide(x) +} +\arguments{ +\item{x}{A \code{repgrid} object.} +} +\description{ +Export a grid to dataframe with wide format +} +\keyword{internal} diff --git a/man/importDataframe.Rd b/man/importDataframe.Rd new file mode 100644 index 0000000..9705e46 --- /dev/null +++ b/man/importDataframe.Rd @@ -0,0 +1,110 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/import.r +\name{importDataframe} +\alias{importDataframe} +\title{Convert a dataframe into a repgrid object.} +\usage{ +importDataframe( + x, + format = "element_columns", + rmin = NULL, + rmax = NULL, + pole_sep = ":" +) +} +\arguments{ +\item{x}{A dataframe. See Detail section and examples for required format.} + +\item{format}{One of \code{element_columns} (default), \code{construct_columns}, or \code{long}. See corresponding sections below.} + +\item{rmin, rmax}{Min and max of rating scale.} + +\item{pole_sep}{Character(s) to seperate the constructs poles (defaults to a colon) for format \code{construct_columns}. +Without a separator, constructs are used as right poles, all left poles will be \code{NA}.} +} +\value{ +A `repgrid`` object. +} +\description{ +There are three different dataframe formats from which a \code{repgrid} object can be created: +Columns are a) \code{element_columns}, b) \code{construct_columns}, c) \code{long}. +Three corresponding sample dataframes, (\link{df_element_columns}, \link{df_construct_columns}, and \link{df_long}) are included +in the package (see examples). See Detail section below for more info. +} +\section{Format \code{element_columns}}{ + + +In this format, each element has a separate column, and each row contains the ratings for one construct. +It is a common way to represent grid data and looks like this. + +\tabular{lccccrr}{ +\code{1} \tab \code{element_1} \tab \code{element_2} \tab \code{element_3} \tab \code{element_4} \tab \code{5} \tab \code{preferred} \cr +\code{left_pole_1} \tab \code{1} \tab \code{5} \tab \code{3} \tab \code{4} \tab \code{right_pole_1} \tab \code{left} \cr +\code{left_pole_2} \tab \code{3} \tab \code{1} \tab \code{1} \tab \code{3} \tab \code{right_pole_2} \tab \code{right} \cr +\code{left_pole_3} \tab \code{4} \tab \code{2} \tab \code{5} \tab \code{1} \tab \code{right_pole_3} \tab \code{NA} \cr +} + +The columns names contains the minimum of the rating scale (\code{1}), the names of the elements (\code{element_1} to +\code{element_4}), the maximum of the rating scale (\code{5}), and optionally the column \code{preferred}, indicating the preferred +pole. Each row contains the constructs entries (left pole, ratings, right pole, preferred pole). The preferred pole +must be one of \code{left}, \code{right}, \code{none}, \code{NA} (see \code{\link[=preferredPoles]{preferredPoles()}}). See sample dataframe \link{df_element_columns}. +} + +\section{Format \code{construct_columns}}{ + + +In this format, each construct has a separate column, and each row contains represents element. This format often +results when summarising data (see examples). It looks like this: + +The first column is named \code{elements} followed by the constructs. The construct poles are separated by a colon by +default (see arg \code{pole_sep}). The rows below contain the elements' entries (element name, ratings). The min and max +of the rating scale should be passed explicitly via the args \code{rmin} and \code{rmax}. See sample dataframe +\link{df_construct_columns}. + +\tabular{lrrr}{ +\code{elements} \tab \code{left_pole_1:right_pole_1} \tab \code{left_pole_2:right_pole_2} \tab \code{left_pole_3:right_pole_3} \cr +\code{element_1} \tab \code{1} \tab \code{5} \tab \code{3} \cr +\code{element_2} \tab \code{3} \tab \code{1} \tab \code{1} \cr +\code{element_3} \tab \code{4} \tab \code{2} \tab \code{5} \cr +} +} + +\section{Format \code{long}}{ + + +The \code{long} format gets its name from the fact, that it has less columns, but many more rows. It is a common format +in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +value. The format looks like this: + +\tabular{lllrlrr}{ +\code{element} \tab \code{left_pole} \tab \code{right_pole} \tab \code{rating} \tab \code{preferred_pole} \tab \code{rmin} \tab \code{rmax} \cr +\verb{element 1} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{1} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_2} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{5} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_3} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{4} \tab \code{left} \tab \code{1} \tab \code{5} \cr +} + +The columns \code{element}, \code{left_pole}, \code{right_pole}, and \code{rating} are mandatory, the columns \code{preferred_pole}, \code{rmin}, +and \code{rmax} are optional. \code{rmin} and \code{rmax} contain the min and max of the rating scale. Alternatively, you may +pass \code{rmin} and \code{rmax} as arguments in the function call. See sample dataframe \link{df_long}. +} + +\examples{ +# dataframe with elements as columns (preferred way) +importDataframe(df_element_columns) + +# dataframe with constructs as columns +importDataframe(df_construct_columns, format = "construct_columns", rmin = 1, rmax = 5) + +# dataframe with long format +importDataframe(df_long, format = "long", rmin = 1, rmax = 5) +} +\seealso{ +Import data +\code{\link{importExcel}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridstat}()}, +\code{\link{importGridsuite}()}, +\code{\link{importScivesco}()}, +\code{\link{importTxt}()} +} +\concept{import} diff --git a/man/importExcel.Rd b/man/importExcel.Rd index 8f1a552..f5875a0 100644 --- a/man/importExcel.Rd +++ b/man/importExcel.Rd @@ -4,73 +4,84 @@ \alias{importExcel} \title{Import grid data from an Excel file.} \usage{ -importExcel(file, dir = NULL, sheet = 1, min = NULL, max = NULL) +importExcel(file, sheet = 1, format = "wide", rmin = NULL, rmax = NULL) } \arguments{ -\item{file}{A vector of filenames including the full path if file is not in current working -directory. The file suffix has to be \code{.xlsx} (used since Excel 2007).} +\item{file}{Path(s) to Excel file(s) (suffix \code{.xlsx}).} -\item{dir}{Alternative way to supply the directory where the file is located -(default \code{NULL}).} +\item{sheet}{Name or index of sheet with grid data.} -\item{sheet}{Name or index of Excel sheet containing the grid.} +\item{format}{Two formats are supported. \code{wide} (default): each column represents one element, each row represent +one constructs. \code{long}: each row contains one rating value for a element-construct combination. See +sections below and examples.} -\item{min}{Optional argument (\code{numeric}, default \code{NULL}) -for minimum rating value in grid.} - -\item{max}{Optional argument (\code{numeric}, default \code{NULL}) -for maximum rating value in grid.} +\item{rmin, rmax}{Min and max of the rating scale (\code{numeric}, default \code{NULL}).} } \value{ -A single \code{repgrid} object in case one file and -a list of \code{repgrid} objects in case multiple files are imported. +A single \code{repgrid} object (one inpput file) or a list of \code{repgrid} objects (several input files). } \description{ -You can define a grid using Microsoft Excel and by saving it as a -\code{.xlsx} file. The \code{.xlsx} file has to be in a specified fixed -format (see section Details). +You can define a grid in a Microsoft Excel file (suffix \code{.xlsx}). The file must have one of +two formats (\code{wide} or \code{long}, see format sections below). } -\details{ -Excel file structure: The first row contains the minimum of the rating scale, -the names of the elements and the maximum of the rating scale. Below every -row contains the left construct pole, the ratings and the right construct -pole. +\section{Format \code{wide}}{ + -\tabular{lccccr}{ -\code{1} \tab \code{E1} \tab \code{E2} \tab \code{E3} \tab \code{E4} \tab \code{5} \cr -\verb{left pole 1} \tab \code{1} \tab \code{5} \tab \code{3} \tab \code{4} \tab \verb{right pole 1} \cr -\verb{left pole 2} \tab \code{3} \tab \code{1} \tab \code{1} \tab \code{3} \tab \verb{right pole 2} \cr -\verb{left pole 3} \tab \code{4} \tab \code{2} \tab \code{5} \tab \code{1} \tab \verb{right pole 3} \cr +In the \code{wide} format, each element has a separate column, and each row contains the ratzings for one construct. +It is a common way to represent grid data and looks like this: + +\tabular{lccccrr}{ +\code{1} \tab \code{element_1} \tab \code{element_2} \tab \code{element_3} \tab \code{element_4} \tab \code{5} \tab \code{preferred} \cr +\code{left_pole_1} \tab \code{1} \tab \code{5} \tab \code{3} \tab \code{4} \tab \code{right_pole_1} \tab \code{left} \cr +\code{left_pole_2} \tab \code{3} \tab \code{1} \tab \code{1} \tab \code{3} \tab \code{right_pole_2} \tab \code{right} \cr +\code{left_pole_3} \tab \code{4} \tab \code{2} \tab \code{5} \tab \code{1} \tab \code{right_pole_3} \tab \code{NA} \cr } -Note that the maximum and minimum value has to be defined using the -\code{min} and \code{max} arguments if no values are supplied at the -beginning and end of the first row. Otherwise the scaling range is inferred -from the available data and a warning is issued as the range may be -erroneous. This may effect other functions that depend on knowing the correct -range and it is thus strongly recommended to set the scale range correctly. +The header row contains the minimum of the rating scale (\code{1}), the names of the elements (\code{element_1} to \code{element_4}), +the maximum of the rating scale (\code{5}), and optionally the column \code{preferred}, indicating the preferred pole. +Each row contains the constructs entries (left pole, ratings, right pole, preferred pole). The preferred pole +must be one of \code{left}, \code{right}, \code{none}, \code{NA} (see \code{\link[=preferredPoles]{preferredPoles()}}). } -\examples{ -\dontrun{ -# Open Excel file delivered along with the package +\section{Format \code{long}}{ + + +The \code{long} format has this name because it has few columns and many rows. It is a common format +in data analytics. Here, each row contains a different element-construct combination and the corresponding rating +value. The format looks like this: + +\tabular{lllrlrr}{ +\code{element} \tab \code{left_pole} \tab \code{right_pole} \tab \code{rating} \tab \code{preferred_pole} \tab \code{rmin} \tab \code{rmax} \cr +\verb{element 1} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{1} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_2} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{5} \tab \code{left} \tab \code{1} \tab \code{5} \cr +\code{element_3} \tab \verb{left pole 1} \tab \verb{right pole 1} \tab \code{4} \tab \code{left} \tab \code{1} \tab \code{5} \cr +} + +The columns \code{element}, \code{left_pole}, \code{right_pole}, and \code{rating} are mandatory, the columns \code{preferred_pole}, \code{rmin}, +and \code{rmax} are optional. \code{rmin} and \code{rmax} contain the min and max of the rating scale. Alternatively, you may +pass \code{rmin} and \code{rmax} as arguments in the function call. +} + +\examples{ file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") -rg <- importExcel(file) +rg_1 <- importExcel(file, sheet = "wide") +rg_2 <- importExcel(file, sheet = "long", format = "long") -# To see the structure of the Excel file try to open it as follows. -# Requires Excel to be installed. -system2("open", file) +# Open Sample file to inspect the two (requires Excel to be installed). +\dontrun{ +browseURL(file) # may not work on all systems } # Import more than one Excel file files <- system.file("extdata", c("grid_01.xlsx", "grid_02.xlsx"), package = "OpenRepGrid") -rg <- importExcel(files) -} - +rgs <- importExcel(files) # returns a list of grids } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, -\code{\link[=importGridstat]{importGridstat()}}, -\code{\link[=importScivesco]{importScivesco()}}, -\code{\link[=importGridsuite]{importGridsuite()}}, -\code{\link[=importTxt]{importTxt()}} +Import data +\code{\link{importDataframe}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridstat}()}, +\code{\link{importGridsuite}()}, +\code{\link{importScivesco}()}, +\code{\link{importTxt}()} } +\concept{import} diff --git a/man/importExcelInternal.Rd b/man/importExcelInternal.Rd deleted file mode 100644 index 0c74e43..0000000 --- a/man/importExcelInternal.Rd +++ /dev/null @@ -1,27 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/import.r -\name{importExcelInternal} -\alias{importExcelInternal} -\title{workhorse function (parser) for importExcel.} -\usage{ -importExcelInternal(file, dir = NULL, sheet = 1, min = NULL, max = NULL) -} -\arguments{ -\item{file}{A vector of filenames including the full path if file is not in current working -directory. The file suffix has to be \code{.xlsx} (used since Excel 2007).} - -\item{dir}{Alternative way to supply the directory where the file is located -(default \code{NULL}).} - -\item{sheet}{Name or index of Excel sheet containing the grid.} - -\item{min}{Optional argument (\code{numeric}, default \code{NULL}) -for minimum rating value in grid.} - -\item{max}{Optional argument (\code{numeric}, default \code{NULL}) -for maximum rating value in grid.} -} -\description{ -workhorse function (parser) for importExcel. -} -\keyword{internal} diff --git a/man/importGridcor.Rd b/man/importGridcor.Rd index 1ff2323..f0f464c 100644 --- a/man/importGridcor.Rd +++ b/man/importGridcor.Rd @@ -50,10 +50,12 @@ for Grid Data (version 4.0). Barcelona: Centro de Terapia Cognitiva. Retrieved from \url{https://repertorygrid.net/en/}. } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, -\code{\link[=importGridstat]{importGridstat()}}, -\code{\link[=importScivesco]{importScivesco()}}, -\code{\link[=importGridsuite]{importGridsuite()}}, -\code{\link[=importTxt]{importTxt()}}, -\code{\link[=importExcel]{importExcel()}} -} +Import data +\code{\link{importDataframe}()}, +\code{\link{importExcel}()}, +\code{\link{importGridstat}()}, +\code{\link{importGridsuite}()}, +\code{\link{importScivesco}()}, +\code{\link{importTxt}()} +} +\concept{import} diff --git a/man/importGridstat.Rd b/man/importGridstat.Rd index ec84cd4..4aa96bd 100644 --- a/man/importGridstat.Rd +++ b/man/importGridstat.Rd @@ -69,6 +69,12 @@ rg <- importGridstat(file, dir, min = 1, max = 6) Bell, R. C. (1998) GRIDSTAT: A program for analyzing the data of a repertory grid. Melbourne: Author. } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, \code{\link[=importGridstat]{importGridstat()}}, \code{\link[=importScivesco]{importScivesco()}}, \code{\link[=importGridsuite]{importGridsuite()}}, \code{\link[=importTxt]{importTxt()}}, -\code{\link[=importExcel]{importExcel()}} +Import data +\code{\link{importDataframe}()}, +\code{\link{importExcel}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridsuite}()}, +\code{\link{importScivesco}()}, +\code{\link{importTxt}()} } +\concept{import} diff --git a/man/importGridsuite.Rd b/man/importGridsuite.Rd index 946900d..b2c7d4a 100644 --- a/man/importGridsuite.Rd +++ b/man/importGridsuite.Rd @@ -51,6 +51,12 @@ Walter, O. B., Bacher, A., & Fromm, M. (2004). A proposal for a common data exc data.\emph{Journal of Constructivist Psychology, 17}(3), 247. \doi{doi:10.1080/10720530490447167} } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, \code{\link[=importGridstat]{importGridstat()}}, \code{\link[=importScivesco]{importScivesco()}}, \code{\link[=importGridsuite]{importGridsuite()}}, \code{\link[=importTxt]{importTxt()}}, -\code{\link[=importExcel]{importExcel()}} -} +Import data +\code{\link{importDataframe}()}, +\code{\link{importExcel}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridstat}()}, +\code{\link{importScivesco}()}, +\code{\link{importTxt}()} +} +\concept{import} diff --git a/man/importScivesco.Rd b/man/importScivesco.Rd index 781cec1..9e1d4b4 100644 --- a/man/importScivesco.Rd +++ b/man/importScivesco.Rd @@ -59,6 +59,12 @@ Menzel, F., Rosenberger, M., Buve, J. (2007). Emotionale, intuitive und rationale Konstrukte verstehen. \emph{Personalfuehrung, 4}(7), 91-99. } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, \code{\link[=importGridstat]{importGridstat()}}, \code{\link[=importScivesco]{importScivesco()}}, \code{\link[=importGridsuite]{importGridsuite()}}, \code{\link[=importTxt]{importTxt()}}, -\code{\link[=importExcel]{importExcel()}} +Import data +\code{\link{importDataframe}()}, +\code{\link{importExcel}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridstat}()}, +\code{\link{importGridsuite}()}, +\code{\link{importTxt}()} } +\concept{import} diff --git a/man/importTxt.Rd b/man/importTxt.Rd index 22d67ba..a0a5619 100644 --- a/man/importTxt.Rd +++ b/man/importTxt.Rd @@ -90,17 +90,23 @@ thus strongly recommended to set the scale range correctly. file <- system.file("extdata", "grid_01.txt", package = "OpenRepGrid") rg <- importTxt(file) -\dontrun{ # To see the structure of the file, try opening it as follows. # (may not work on all systems) -file.show(file) +\dontrun{ file.show(file) } # Import more than one .txt file files <- system.file("extdata", c("grid_01.txt", "grid_02.txt"), package = "OpenRepGrid") rgs <- importTxt(files) + } \seealso{ -\code{\link[=importGridcor]{importGridcor()}}, \code{\link[=importGridstat]{importGridstat()}}, \code{\link[=importScivesco]{importScivesco()}}, \code{\link[=importGridsuite]{importGridsuite()}}, \code{\link[=importTxt]{importTxt()}}, -\code{\link[=importExcel]{importExcel()}} +Import data +\code{\link{importDataframe}()}, +\code{\link{importExcel}()}, +\code{\link{importGridcor}()}, +\code{\link{importGridstat}()}, +\code{\link{importGridsuite}()}, +\code{\link{importScivesco}()} } +\concept{import} diff --git a/man/importTxtInternal.Rd b/man/importTxtInternal.Rd deleted file mode 100644 index 317a21b..0000000 --- a/man/importTxtInternal.Rd +++ /dev/null @@ -1,92 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/import.r -\name{importTxtInternal} -\alias{importTxtInternal} -\title{ImportTxtInternal is the parser for importTxt.} -\usage{ -importTxtInternal(file, dir = NULL, min = NULL, max = NULL) -} -\arguments{ -\item{file}{Filename including path if file is not in current working -directory. File can also be a complete URL. The fileformat -is \code{.txt}.} - -\item{dir}{Alternative way to supply the directory where the file is located -(default \code{NULL}).} - -\item{min}{Optional argument (\code{numeric}, default \code{NULL}) -for minimum rating value in grid.} - -\item{max}{Optional argument (\code{numeric}, default \code{NULL}) -for maximum rating value in grid.} -} -\value{ -List of relevant data. -} -\description{ -ImportTxtInternal is the parser for importTxt that constructs an import object. The \code{.txt} file has to be in a fixed -format. There are three mandatory blocks each starting and ending with a predefined tag in uppercase letters. The -first block starts with \code{ELEMENTS} and ends with \verb{END ELEMENTS} and contains one element in each line. The other -mandatory blocks contain the constructs and ratings (see below). In the block containing the constructs the left and -right pole are separated by a colon (:). To define missing values use \code{NA} like in the example below. One optional -block contains the range of the rating scale used defined by two numbers. The order of the blocks is arbitrary. All -text not contained within the blocks is discarded and can thus be used for comments. -} -\details{ -\if{html}{\out{
}}\preformatted{---------------- sample .txt file ------------------- - - Note: anything outside the tag pairs is discarded - -ELEMENTS -element 1 -element 2 -element 3 -END ELEMENTS - -CONSTRUCTS -left pole 1 : right pole 1 -left pole 2 : right pole 2 -left pole 3 : right pole 3 -left pole 4 : right pole 4 -END CONSTRUCTS - -RATINGS -1 3 2 -4 1 1 -1 4 4 -3 1 1 -END RATINGS - -RANGE -1 4 -END RANGE - ------------------- end of file ------------------ -}\if{html}{\out{
}} - -Note that the maximum and minimum value has to be defined using the \code{min} and -\code{max} arguments if no \code{RANGE} block is contained in the data file. -Otherwise the scaling range is inferred from the available data and a warning -is issued as the range may be erroneous. This may effect other functions that -depend on knowing the correct range and it is thus strongly recommended to -set the scale range correctly. - -Question marks (?) in the ratings are treated as missing data. -} -\examples{ -\dontrun{ - -# supposing that the data file sample.txt is in the current directory -file <- "sample.txt" -imp <- importTxtInternal(file) - -# specifying a directory (arbitrary example directory) -dir <- "/Users/markheckmann/data" -imp <- importTxtInternal(file, dir) - -# using a full path -imp <- importTxtInternal("/Users/markheckmann/data/sample.txt") -} - -} -\keyword{internal} diff --git a/man/roxygen/meta.R b/man/roxygen/meta.R index 44900ab..4eef351 100644 --- a/man/roxygen/meta.R +++ b/man/roxygen/meta.R @@ -1,3 +1,3 @@ list( - rd_family_title = list(align_constructs = "Aligning constructs") + rd_family_title = list(align_constructs = "Aligning constructs", import = "Import data", grid_dataframe = "Other grid dataframes: ") ) diff --git a/vignettes/web/datasets.Rmd b/vignettes/web/datasets.Rmd index 2b15eb3..7cfb0ab 100644 --- a/vignettes/web/datasets.Rmd +++ b/vignettes/web/datasets.Rmd @@ -32,6 +32,8 @@ data set name | description and source `slater1977a` | drug addict’s grid dataset from (Slater, 1977, p. 32). `slater1977b` | grid dataset (ranked) from a seventeen year old female psychiatric patient (Slater, 1977, p. 110) showing depression, anxiety and self-mutilation. The data was originally reported by Watson (1970). +You can also get an overview by typing `data(package = "OpenRepGrid")` into the console. + ### R-Code To display one of the grid just type the grid's name into the R console. From 086bd717eeef1de60e441dc66cc038e315f81658 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Sun, 6 Jul 2025 17:06:31 +0200 Subject: [PATCH 16/28] tests for import & export (xlsx, dataframe) --- R/dev-functions.r | 2 +- R/repgrid-basicops.r | 6 ++--- .../{test-import.R => test-import-export.R} | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) rename tests/testthat/{test-import.R => test-import-export.R} (67%) diff --git a/R/dev-functions.r b/R/dev-functions.r index 4fd6888..1252be5 100644 --- a/R/dev-functions.r +++ b/R/dev-functions.r @@ -55,7 +55,7 @@ randomGrid <- function(nc = 10, ne = 15, nwc = 8, nwe = 5, range = c(1, 5), prob scores = scores ) x <- makeRepgrid(args) - setScale(x, min = range[1], max = range[2], step = 1) + setScale(x, min = range[1], max = range[2]) } diff --git a/R/repgrid-basicops.r b/R/repgrid-basicops.r index a7a4262..b6f1b9b 100644 --- a/R/repgrid-basicops.r +++ b/R/repgrid-basicops.r @@ -510,9 +510,9 @@ setScale <- function(x, min, max, step, ...) { # ... needes for makeRepgrid call } x@scale$max <- max } - if (!missing(step)) { - x@scale$step <- step - } + # if (!missing(step)) { + # x@scale$step <- step + # } x } # setScale(x, min=1, max=5, step=1) diff --git a/tests/testthat/test-import.R b/tests/testthat/test-import-export.R similarity index 67% rename from tests/testthat/test-import.R rename to tests/testthat/test-import-export.R index 64a4b04..8855e95 100644 --- a/tests/testthat/test-import.R +++ b/tests/testthat/test-import-export.R @@ -31,6 +31,19 @@ test_that("importTxt - RATINGS", { # EXCEL -------------------------------------------- +test_that("export-import - roundtrip", { + g_orig <- boeker + + file_wide <- saveAsExcel(g_orig, file = tempfile(fileext = ".xlsx"), format = "wide") + g_wide <- importExcel(file_wide, format = "wide") + expect_identical(g_orig, g_wide) + + file_long <- saveAsExcel(g_orig, file = tempfile(fileext = ".xlsx"), format = "long") + g_long <- importExcel(file_long, format = "long") + expect_identical(g_orig, g_long) +}) + + test_that("importExcel - PREFERRED", { path <- test_path("testdata/grids.xlsx") @@ -48,3 +61,17 @@ test_that("importExcel - PREFERRED", { importExcel(path, sheet = "preferred incorrect 1") ) }) + + +# DATAFRAME -------------------------------------------- + +test_that("importDataframe", { + # sample dataframes yield same results + g1 <- importDataframe(df_element_columns) + g2 <- importDataframe(df_construct_columns, format = "c", rmin = 1, rmax = 5) + preferredPoles(g2) <- c("l", "r", "n") + g3 <- importDataframe(df_long, format = "long") + + expect_identical(g1, g2) + expect_identical(g1, g3) +}) From bff90d2e4086a0056732fc9c7bf911bf703b1864 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Sun, 6 Jul 2025 20:14:34 +0200 Subject: [PATCH 17/28] bertinBase: restore changed global par() settings --- R/bertin.r | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/R/bertin.r b/R/bertin.r index dd011eb..fcdba87 100644 --- a/R/bertin.r +++ b/R/bertin.r @@ -335,7 +335,7 @@ bertinBase <- function(nrow, ncol, labels = "", labels.elements = "", } colorRow <- function(cr) { - par(new = TRUE) # next plot will overplot not earse the old one, necessary for setting the same regions + old_par <- par(new = TRUE) # next plot will overplot not erase the old one, necessary for setting the same regions plot.new() # plot.window(xlim=0:1, ylim=0:1) #, xaxs="i", yaxs="i")#, asp =nrow/ncol) if (cr >= 1 & cr <= nrow) { # color current row cr @@ -348,10 +348,11 @@ bertinBase <- function(nrow, ncol, labels = "", labels.elements = "", labels = labels.rows, col = col.mark.text, cex = cex.text ) } + par(old_par) } colorColumn <- function(cc) { - par(new = TRUE) # next plot will overplot not earse the old one, necessary for setting the same regions + old_par <- par(new = TRUE) # next plot will overplot not earse the old one, necessary for setting the same regions plot.new() # plot.window(xlim=0:1, ylim=0:1) #, xaxs="i", yaxs="i")#, asp =nrow/ncol) if (cc >= 1 & cc <= ncol) { # color current column cc @@ -373,6 +374,7 @@ bertinBase <- function(nrow, ncol, labels = "", labels.elements = "", segments(x.lines[cc], y1.lines, x.lines[cc], y2.lines[cc], lwd = 3, col = "white") # overplot old stroke in white segments(x.lines[cc], y1.lines, x.lines[cc], y2.lines[cc], col = col.mark.fill) } + par(old_par) } renewColumn <- function(cc) { @@ -440,7 +442,7 @@ bertinBase <- function(nrow, ncol, labels = "", labels.elements = "", # set plotting parameters # old.par <- par(no.readonly = TRUE) # save parameters # on.exit(par(old.par)) # reset old par when done - op <- par(oma = rep(0, 4), mar = rep(0, 4), xaxs = "i", yaxs = "i") + old_par <- par(oma = rep(0, 4), mar = rep(0, 4), xaxs = "i", yaxs = "i") if (print) { # in case no new printing should occur par(new = FALSE) } else { @@ -466,7 +468,7 @@ bertinBase <- function(nrow, ncol, labels = "", labels.elements = "", colorRow(cr) colorColumn(cc) } - # par(op) + par(old_par) invisible(NULL) } From c22881caf146af355f5a264a71f9a0482e7a0ed5 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 18:41:03 +0200 Subject: [PATCH 18/28] feat: saveAsExcel() saves gridlist (#67), saveAsWorksheet() * `saveAsExcel` can export a list of grids now (#67) * `saveAsWorksheet` to add grid as anew to an in `openxlsx` `Workbook` object. --- DESCRIPTION | 4 +- NAMESPACE | 1 + NEWS.md | 2 + R/export.r | 166 ++++++++++++++++++---- R/gridlist.R | 5 + R/measures.r | 1 - R/repgrid-basicops.r | 7 + R/utils.r | 12 ++ inst/examples/example-save-as-excel.R | 29 ++++ inst/examples/example-save-as-worksheet.R | 17 +++ man/saveAsExcel.Rd | 33 +++-- man/saveAsWorksheet.Rd | 49 +++++++ tests/testthat/test-gridlist.R | 7 + tests/testthat/test-utils.R | 13 ++ 14 files changed, 308 insertions(+), 38 deletions(-) create mode 100644 inst/examples/example-save-as-excel.R create mode 100644 inst/examples/example-save-as-worksheet.R create mode 100644 man/saveAsWorksheet.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 394f70d..378ef20 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,8 +16,8 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9009 -Date: 2025-07-05 +Version: 0.1.18.9010 +Date: 2025-07-07 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid Imports: diff --git a/NAMESPACE b/NAMESPACE index 9ab2eae..73c9de2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -178,6 +178,7 @@ export(ring) export(sapply_pb) export(saveAsExcel) export(saveAsTxt) +export(saveAsWorksheet) export(setConstructAttr) export(setElementAttr) export(setMeta) diff --git a/NEWS.md b/NEWS.md index 4f02a67..3af40db 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # OpenRepGrid 0.1.18 (dev version) +* `saveAsExcel` can export a list of grids now (#67) +* `saveAsWorksheet` to add grid as anew to an in `openxlsx` `Workbook` object. * `importExcel` now also understands the long format (#65) * `importDataframe` converts a dataframe into a repgrid. Three different formats can be read in. See the sample dataframes `df_element_columns`, `df_construct_columns`, and `df_long` (#61) diff --git a/R/export.r b/R/export.r index 7a98f9f..3c9c178 100644 --- a/R/export.r +++ b/R/export.r @@ -171,39 +171,157 @@ saveAsTxt <- function(x, file = NA) { ############################# EXPORT EXCEL #################################### -#' Save grid as Microsoft Excel file (.xlsx) +#' Save grids as Microsoft Excel file (.xlsx) #' -#' `saveAsExcel` will save the grid as a Microsoft Excel file (`.xlsx`). +#' `saveAsExcel` will save one or more grids as MS Excel file (`.xlsx`). #' -#' @param x A `repgrid` object. +#' @param x A `repgrid` object or a list of grids. #' @param file File path. Suffix must be `.xlsx`. #' @param format Two output formats are supported: `wide` (default) where each column represents one element, each row #' represent one constructs (a common grid representation), and `long` where each row contains an element-construct #' combination and the corresponding rating value. See [importExcel()] for details and examples. -#' @param sheet Optional sheet name. If `NULL` (default), either `"grid (wide format)"` or `"grid (long format)"`. +#' @param sheet Sheet name (defaults to `grid`). If `x` is a list of grids, the name of the list entry is used. +#' If it has no name, a sequential index is appended to `sheet`. #' @return Invisibly returns file path. #' @export -#' @seealso [importExcel()] -#' @examples -#' # save grid in wide format (default) -#' file <- tempfile(fileext = ".xlsx") -#' saveAsExcel(boeker, file) -#' \dontrun{ -#' browseURL(file) # open file, requires Excel, may not work on all system -#' } +#' @seealso [importExcel()], [saveAsWorksheet()] +#' @example inst/examples/example-save-as-excel.R #' -#' # save grid in log format -#' file <- tempfile(fileext = ".xlsx") -#' saveAsExcel(boeker, file, format = "long") -#' \dontrun{ -#' browseURL(file) -#' } -saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { - stop_if_not_is_repgrid(x) +saveAsExcel <- function(x, file, format = "wide", sheet = "grid") { ext <- tools::file_ext(file) if (ext != "xlsx") { stop("The file extension must be '.xlsx'. Found '", ext, "' instead.", call. = FALSE) } + wb <- openxlsx::createWorkbook() + wb <- saveAsWorksheet(x, wb = wb, format = format, sheet = sheet) + openxlsx::saveWorkbook(wb, file, overwrite = TRUE) + invisible(file) +} + + +#' Add grids as sheets to an openxlsx Workbook +#' +#' `saveAsWorksheet` will add one or more grids to an a [openxlsx](https://CRAN.R-project.org/package=openxlsx) +#' `Workbook` object. +#' +#' @param x A `repgrid` object or a list of grids. +#' @param wb A [openxlsx](https://CRAN.R-project.org/package=openxlsx) `Workbook` object. +#' @inheritParams saveAsExcel +#' @return Invisibly returns Workbook object. +#' @export +#' @seealso [saveAsExcel()] +#' @example inst/examples/example-save-as-worksheet.R +#' +saveAsWorksheet <- function(x, wb, format = "wide", sheet = "grid") { + stop_if_not_inherits(wb, "Workbook") + + if (!is_list_of_repgrids(x)) { + wb <- add_one_sheet_with_grid(x, wb = wb, format = format, sheet = sheet) + } else { + ii <- seq_along(x) + list_names <- get_names_na(x) + sheets_numbered <- paste(sheet %||% "grid", ii) + sheets <- ifelse(!is.na(list_names), list_names, sheets_numbered) + for (i in ii) { + wb <- add_one_sheet_with_grid(x[[i]], wb = wb, format = format, sheet = sheets[i]) + } + } + invisible(wb) +} + + + +# saveAsExcelv2 <- function(x, file, format = "wide", sheet = "grid") { +# ext <- tools::file_ext(file) +# if (ext != "xlsx") { +# stop("The file extension must be '.xlsx'. Found '", ext, "' instead.", call. = FALSE) +# } +# if (is.null(wb)) { +# wb <- openxlsx::createWorkbook() +# } +# if (!is_list_of_repgrids(x)) { +# wb <- add_one_sheet_with_grid(x, wb = wb, format = format, sheet = sheet) +# } else { +# ii <- seq_along(x) +# list_names <- get_names_na(x) +# sheets_numbered <- paste(sheet %||% "grid", ii) +# sheets <- ifelse(is.na(list_names), sheets_numbered) +# for (i in ii) { +# wb <- add_one_sheet_with_grid(x[[i]], wb = wb, format = format, sheet = sheets[i]) +# } +# } +# openxlsx::saveWorkbook(wb, file, overwrite = TRUE) +# invisible(file) +# } +# +# saveAsExcel_v1 <- function(x, file, format = "wide", sheet = NULL) { +# if (is_list_of_repgrids(x)) { +# +# } +# +# stop_if_not_is_repgrid(x) +# ext <- tools::file_ext(file) +# if (ext != "xlsx") { +# stop("The file extension must be '.xlsx'. Found '", ext, "' instead.", call. = FALSE) +# } +# format <- match.arg(tolower(format), c("wide", "long")) +# +# if (format == "wide") { +# df <- grid_to_df_wide(x) +# sheet <- sheet %||% "grid (wide format)" +# jj_rows <- seq_len(nrow(df) + 1) +# jj_elements <- seq_len(ncol(x)) + 1 +# j_left_pole <- 1 +# j_right_pole <- ncol(x) + 2 +# j_preferred <- ncol(df) +# +# style_header <- openxlsx::createStyle(textDecoration = "bold", fgFill = "grey90", border = "bottom") +# style_center <- openxlsx::createStyle(halign = "center") +# style_pole_left <- openxlsx::createStyle(textDecoration = "bold", halign = "right", border = "right") +# style_pole_right <- openxlsx::createStyle(textDecoration = "bold", halign = "left", border = "left") +# style_text_grey <- openxlsx::createStyle(fontColour = "grey50") +# +# wb <- openxlsx::createWorkbook() +# +# openxlsx::addWorksheet(wb, sheet) +# openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_center, rows = jj_rows, cols = jj_elements, stack = TRUE, gridExpand = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_pole_left, rows = jj_rows, cols = j_left_pole, stack = TRUE, gridExpand = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_pole_right, rows = jj_rows, cols = j_right_pole, stack = TRUE, gridExpand = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_text_grey, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) +# openxlsx::setColWidths(wb, sheet, cols = c(j_left_pole, j_right_pole, j_preferred), widths = c(20, 20, 13)) +# openxlsx::saveWorkbook(wb, file, overwrite = TRUE) +# } else { +# df <- grid_to_df_long(x) +# sheet <- sheet %||% "grid (long format)" +# jj_rows <- seq_len(nrow(df) + 1) +# jj_cols <- seq_len(ncol(df)) +# jj_cols_optional <- 5:7 +# j_preferred <- 5 +# ii_end_construct <- rle(df$left_pole)$lengths %>% cumsum() %>% head(-1) + 1 +# +# style_header <- openxlsx::createStyle(textDecoration = "bold", fgFill = "grey90", border = "bottom") +# style_border_left <- openxlsx::createStyle(border = "left") +# style_border_bottom <- openxlsx::createStyle(border = "bottom", borderStyle = "dashed") +# style_text_grey <- openxlsx::createStyle(fontColour = "grey50") +# +# wb <- openxlsx::createWorkbook() +# openxlsx::addWorksheet(wb, sheet) +# openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_border_left, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_text_grey, rows = jj_rows, cols = jj_cols_optional, stack = TRUE, gridExpand = TRUE) +# openxlsx::addStyle(wb, sheet, style = style_border_bottom, rows = ii_end_construct, cols = jj_cols, stack = TRUE, gridExpand = TRUE) +# openxlsx::setColWidths(wb, sheet, cols = jj_cols, widths = c(20, 20, 20, 10, 13, 10, 10)) +# openxlsx::freezePane(wb, sheet, firstActiveRow = 2) +# openxlsx::saveWorkbook(wb, file, overwrite = TRUE) +# } +# invisible(file) +# } + +add_one_sheet_with_grid <- function(x, wb, format = "wide", sheet = NULL) { + stop_if_not_is_repgrid(x) + stop_if_not_inherits(wb, "Workbook") + format <- match.arg(tolower(format), c("wide", "long")) if (format == "wide") { @@ -221,8 +339,6 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { style_pole_right <- openxlsx::createStyle(textDecoration = "bold", halign = "left", border = "left") style_text_grey <- openxlsx::createStyle(fontColour = "grey50") - wb <- openxlsx::createWorkbook() - openxlsx::addWorksheet(wb, sheet) openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) openxlsx::addStyle(wb, sheet, style = style_center, rows = jj_rows, cols = jj_elements, stack = TRUE, gridExpand = TRUE) @@ -230,7 +346,6 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { openxlsx::addStyle(wb, sheet, style = style_pole_right, rows = jj_rows, cols = j_right_pole, stack = TRUE, gridExpand = TRUE) openxlsx::addStyle(wb, sheet, style = style_text_grey, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) openxlsx::setColWidths(wb, sheet, cols = c(j_left_pole, j_right_pole, j_preferred), widths = c(20, 20, 13)) - openxlsx::saveWorkbook(wb, file, overwrite = TRUE) } else { df <- grid_to_df_long(x) sheet <- sheet %||% "grid (long format)" @@ -245,8 +360,6 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { style_border_bottom <- openxlsx::createStyle(border = "bottom", borderStyle = "dashed") style_text_grey <- openxlsx::createStyle(fontColour = "grey50") - wb <- openxlsx::createWorkbook() - sheet <- "grid (long format)" openxlsx::addWorksheet(wb, sheet) openxlsx::writeData(wb, sheet, x = df, headerStyle = style_header, rowNames = FALSE, colNames = TRUE) openxlsx::addStyle(wb, sheet, style = style_border_left, rows = jj_rows, cols = j_preferred, stack = TRUE, gridExpand = TRUE) @@ -254,9 +367,8 @@ saveAsExcel <- function(x, file, format = "wide", sheet = NULL) { openxlsx::addStyle(wb, sheet, style = style_border_bottom, rows = ii_end_construct, cols = jj_cols, stack = TRUE, gridExpand = TRUE) openxlsx::setColWidths(wb, sheet, cols = jj_cols, widths = c(20, 20, 20, 10, 13, 10, 10)) openxlsx::freezePane(wb, sheet, firstActiveRow = 2) - openxlsx::saveWorkbook(wb, file, overwrite = TRUE) } - invisible(file) + wb } diff --git a/R/gridlist.R b/R/gridlist.R index 3356c19..7b4e8b7 100644 --- a/R/gridlist.R +++ b/R/gridlist.R @@ -104,3 +104,8 @@ rep.repgrid <- function(x, n = 1, ...) { l <- replicate(n, x) as.gridlist(l) } + + +is_list_of_repgrids <- function(x) { + is.list(x) && all(vapply(x, is.repgrid, logical(1))) +} diff --git a/R/measures.r b/R/measures.r index 84f11a6..d88061b 100644 --- a/R/measures.r +++ b/R/measures.r @@ -397,7 +397,6 @@ indexPvaff <- function(x, method = 1) { #' @example inst/examples/example-indexBieri.R #' @export #' -#' indexBieri <- function(x, deviation = 0) { stop_if_not_is_repgrid(x) diff --git a/R/repgrid-basicops.r b/R/repgrid-basicops.r index b6f1b9b..47a6489 100644 --- a/R/repgrid-basicops.r +++ b/R/repgrid-basicops.r @@ -96,6 +96,13 @@ stop_if_not_integerish <- function(x, arg = NULL) { } +stop_if_not_inherits <- function(x, what, argname = "x") { + if (!inherits(x, what)) { + stop("`", argname, "` must have class <", what, "> not <", class(x)[1], ">", call. = FALSE) + } +} + + ############################# EXTRACT AND SET ################################# ## S4 methods diff --git a/R/utils.r b/R/utils.r index 7455d5e..239ef52 100644 --- a/R/utils.r +++ b/R/utils.r @@ -1030,3 +1030,15 @@ list_to_dataframe <- function(l) { b } } + + +# Get list names +# returns vector with same length as list. NA if list entry has no name. +get_names_na <- function(x) { + nm <- names(x) + if (is.null(nm)) { + rep(NA_character_, length(x)) + } else { + ifelse(nzchar(nm), nm, NA_character_) + } +} diff --git a/inst/examples/example-save-as-excel.R b/inst/examples/example-save-as-excel.R new file mode 100644 index 0000000..c2b31b2 --- /dev/null +++ b/inst/examples/example-save-as-excel.R @@ -0,0 +1,29 @@ +# save one grid in wide format (default) +file <- tempfile(fileext = ".xlsx") +saveAsExcel(boeker, file) +\dontrun{ +browseURL(file) # open file, requires Excel, may not work on all system +} + +# save one grid in log format +file <- tempfile(fileext = ".xlsx") +saveAsExcel(boeker, file, format = "long") +\dontrun{ +browseURL(file) +} + +# save a list of grids +file <- tempfile(fileext = ".xlsx") +l <- list(boeker, feixas2004, bell2010) +saveAsExcel(l, file) +\dontrun{ + browseURL(file) +} + +# pass some sheet names (2nd with named sheet) +file <- tempfile(fileext = ".xlsx") +l <- list(boeker, "feixas' grid" = feixas2004) +saveAsExcel(l, file) +\dontrun{ + browseURL(file) +} diff --git a/inst/examples/example-save-as-worksheet.R b/inst/examples/example-save-as-worksheet.R new file mode 100644 index 0000000..0b480b7 --- /dev/null +++ b/inst/examples/example-save-as-worksheet.R @@ -0,0 +1,17 @@ +library(openxlsx) + +wb <- createWorkbook() + +# add grid to worksheet +saveAsWorksheet(boeker, wb, sheet = "boeker") + +# add several grids (2nd has a name) +l <- list(boeker, "feixas' grid" = feixas2004) # +saveAsWorksheet(l, wb) # name sheet + +file <- tempfile(fileext = ".xlsx") +saveWorkbook(wb, file) + +\dontrun{ + browseURL(file) # may not work on all systems +} diff --git a/man/saveAsExcel.Rd b/man/saveAsExcel.Rd index cb11e2a..6e8823e 100644 --- a/man/saveAsExcel.Rd +++ b/man/saveAsExcel.Rd @@ -2,12 +2,12 @@ % Please edit documentation in R/export.r \name{saveAsExcel} \alias{saveAsExcel} -\title{Save grid as Microsoft Excel file (.xlsx)} +\title{Save grids as Microsoft Excel file (.xlsx)} \usage{ -saveAsExcel(x, file, format = "wide", sheet = NULL) +saveAsExcel(x, file, format = "wide", sheet = "grid") } \arguments{ -\item{x}{A \code{repgrid} object.} +\item{x}{A \code{repgrid} object or a list of grids.} \item{file}{File path. Suffix must be \code{.xlsx}.} @@ -15,29 +15,46 @@ saveAsExcel(x, file, format = "wide", sheet = NULL) represent one constructs (a common grid representation), and \code{long} where each row contains an element-construct combination and the corresponding rating value. See \code{\link[=importExcel]{importExcel()}} for details and examples.} -\item{sheet}{Optional sheet name. If \code{NULL} (default), either \code{"grid (wide format)"} or \code{"grid (long format)"}.} +\item{sheet}{Sheet name (defaults to \code{grid}). If \code{x} is a list of grids, the name of the list entry is used. +If it has no name, a sequential index is appended to \code{sheet}.} } \value{ Invisibly returns file path. } \description{ -\code{saveAsExcel} will save the grid as a Microsoft Excel file (\code{.xlsx}). +\code{saveAsExcel} will save one or more grids as MS Excel file (\code{.xlsx}). } \examples{ -# save grid in wide format (default) +# save one grid in wide format (default) file <- tempfile(fileext = ".xlsx") saveAsExcel(boeker, file) \dontrun{ browseURL(file) # open file, requires Excel, may not work on all system } -# save grid in log format +# save one grid in log format file <- tempfile(fileext = ".xlsx") saveAsExcel(boeker, file, format = "long") \dontrun{ browseURL(file) } + +# save a list of grids +file <- tempfile(fileext = ".xlsx") +l <- list(boeker, feixas2004, bell2010) +saveAsExcel(l, file) +\dontrun{ + browseURL(file) +} + +# pass some sheet names (2nd with named sheet) +file <- tempfile(fileext = ".xlsx") +l <- list(boeker, "feixas' grid" = feixas2004) +saveAsExcel(l, file) +\dontrun{ + browseURL(file) +} } \seealso{ -\code{\link[=importExcel]{importExcel()}} +\code{\link[=importExcel]{importExcel()}}, \code{\link[=saveAsWorksheet]{saveAsWorksheet()}} } diff --git a/man/saveAsWorksheet.Rd b/man/saveAsWorksheet.Rd new file mode 100644 index 0000000..1c39b57 --- /dev/null +++ b/man/saveAsWorksheet.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/export.r +\name{saveAsWorksheet} +\alias{saveAsWorksheet} +\title{Add grids as sheets to an openxlsx Workbook} +\usage{ +saveAsWorksheet(x, wb, format = "wide", sheet = "grid") +} +\arguments{ +\item{x}{A \code{repgrid} object or a list of grids.} + +\item{wb}{A \href{https://CRAN.R-project.org/package=openxlsx}{openxlsx} \code{Workbook} object.} + +\item{format}{Two output formats are supported: \code{wide} (default) where each column represents one element, each row +represent one constructs (a common grid representation), and \code{long} where each row contains an element-construct +combination and the corresponding rating value. See \code{\link[=importExcel]{importExcel()}} for details and examples.} + +\item{sheet}{Sheet name (defaults to \code{grid}). If \code{x} is a list of grids, the name of the list entry is used. +If it has no name, a sequential index is appended to \code{sheet}.} +} +\value{ +Invisibly returns Workbook object. +} +\description{ +\code{saveAsWorksheet} will add one or more grids to an a \href{https://CRAN.R-project.org/package=openxlsx}{openxlsx} +\code{Workbook} object. +} +\examples{ +library(openxlsx) + +wb <- createWorkbook() + +# add grid to worksheet +saveAsWorksheet(boeker, wb, sheet = "boeker") + +# add several grids (2nd has a name) +l <- list(boeker, "feixas' grid" = feixas2004) # +saveAsWorksheet(l, wb) # name sheet + +file <- tempfile(fileext = ".xlsx") +saveWorkbook(wb, file) + +\dontrun{ + browseURL(file) # may not work on all systems +} +} +\seealso{ +\code{\link[=saveAsExcel]{saveAsExcel()}} +} diff --git a/tests/testthat/test-gridlist.R b/tests/testthat/test-gridlist.R index 2a16861..4c9c0e0 100644 --- a/tests/testthat/test-gridlist.R +++ b/tests/testthat/test-gridlist.R @@ -1,5 +1,12 @@ test_that("gridlist works correctly", { + + l <- list(boeker, feixas2004) + expect_true(is_list_of_repgrids(l)) + l2 <- append(l, "hello") + expect_false(is_list_of_repgrids(l2)) + gl <- gridlist(boeker, feixas2004) + expect_true(is_list_of_repgrids(gl)) expect_s3_class(gl, "gridlist") expect_length(gl, 2) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index d511ba4..7745f7f 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -27,3 +27,16 @@ test_that("fortify_element_*", { expect_error(fortify_element_id(x, -1)) expect_error(fortify_element_name(x, "xxx")) }) + + +test_that("get_names_na*", { + l1 <- as.list(1:3) + expect_equal(get_names_na(l1), rep(NA_character_, 3)) + + l2 <- list(a = 1, b = 2, 3) + expect_equal(get_names_na(l2), c("a", "b", NA)) + + l3 <- setNames(list(1,2,3), c("x", "", "z")) + expect_equal(get_names_na(l3), c("x", NA, "z")) +}) + From 0057a12b9406a8e84a08aa4a58a36a237431693a Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 19:00:49 +0200 Subject: [PATCH 19/28] tests: saveAsExcel(), saveAsWorksheet() --- R/export.r | 9 ++++++--- tests/testthat/test-save.R | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/testthat/test-save.R diff --git a/R/export.r b/R/export.r index 3c9c178..5597c1e 100644 --- a/R/export.r +++ b/R/export.r @@ -318,15 +318,19 @@ saveAsWorksheet <- function(x, wb, format = "wide", sheet = "grid") { # invisible(file) # } -add_one_sheet_with_grid <- function(x, wb, format = "wide", sheet = NULL) { +add_one_sheet_with_grid <- function(x, wb, format = "wide", sheet = "grid") { stop_if_not_is_repgrid(x) stop_if_not_inherits(wb, "Workbook") format <- match.arg(tolower(format), c("wide", "long")) + sheet <- sheet %||% "grid" + if (sheet %in% names(wb)) { + stop("Worksheet ", shQuote(sheet), " already exists", call. = FALSE) + } + if (format == "wide") { df <- grid_to_df_wide(x) - sheet <- sheet %||% "grid (wide format)" jj_rows <- seq_len(nrow(df) + 1) jj_elements <- seq_len(ncol(x)) + 1 j_left_pole <- 1 @@ -348,7 +352,6 @@ add_one_sheet_with_grid <- function(x, wb, format = "wide", sheet = NULL) { openxlsx::setColWidths(wb, sheet, cols = c(j_left_pole, j_right_pole, j_preferred), widths = c(20, 20, 13)) } else { df <- grid_to_df_long(x) - sheet <- sheet %||% "grid (long format)" jj_rows <- seq_len(nrow(df) + 1) jj_cols <- seq_len(ncol(df)) jj_cols_optional <- 5:7 diff --git a/tests/testthat/test-save.R b/tests/testthat/test-save.R new file mode 100644 index 0000000..97d0732 --- /dev/null +++ b/tests/testthat/test-save.R @@ -0,0 +1,40 @@ +require(openxlsx) + + +test_that("saveAsExcel", { + file <- saveAsExcel(boeker, tempfile(fileext = ".xlsx")) + expect_equal(getSheetNames(file), "grid") + + rgs <- randomGrids(nc = 3) + file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx")) + expect_equal(getSheetNames(file), paste("grid", 1:3)) + + rgs <- randomGrids(nc = 3) + file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx"), sheet = "xxxx") + expect_equal(getSheetNames(file), paste("xxxx", 1:3)) + + names(rgs) <- c("my grid", NA, NA) + file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx")) + expect_equal(getSheetNames(file), c("my grid", "grid 2", "grid 3")) +}) + + +test_that("saveAsWorkbook", { + wb <- createWorkbook() + saveAsWorksheet(boeker, wb) + expect_equal(names(wb), "grid") + + wb <- createWorkbook() + rgs <- randomGrids(nc = 3) + saveAsWorksheet(rgs, wb) + expect_equal(names(wb), paste("grid", 1:3)) + + wb <- createWorkbook() + names(rgs) <- c("my grid", NA, NA) + saveAsWorksheet(rgs, wb, sheet = "xxxx") + expect_equal(names(wb), c("my grid", "xxxx 2", "xxxx 3")) + + wb <- createWorkbook() + saveAsWorksheet(boeker, wb) + expect_error(saveAsWorksheet(boeker, wb), "Worksheet 'grid' already exists") +}) From 84e8cb1afa90434f7954fe873e724969b6682b85 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 19:03:36 +0200 Subject: [PATCH 20/28] run styler --- R/data-openrepgrid.r | 6 +++--- R/export.r | 4 +++- R/import.r | 31 +++++++++++++++++++------------ R/utils.r | 2 +- man/df_construct_columns.Rd | 2 +- man/importTxt.Rd | 3 ++- tests/testthat/test-calc.R | 1 - tests/testthat/test-gridlist.R | 1 - tests/testthat/test-utils.R | 3 +-- tests/testthat/test_biplot.R | 1 - 10 files changed, 30 insertions(+), 24 deletions(-) diff --git a/R/data-openrepgrid.r b/R/data-openrepgrid.r index 898e26e..12029b0 100644 --- a/R/data-openrepgrid.r +++ b/R/data-openrepgrid.r @@ -4,7 +4,7 @@ # # ////////////////////////////////////////////////////////////////////////////// -#_____________ ---- +# _____________ ---- # REPGRID ---- ## Bell (2010) ---- @@ -559,7 +559,7 @@ NULL # save("slater1977b", file="../data/slater1977b.RData") -#_____________ ---- +# _____________ ---- # DATAFRAME ---- ## df_element_columns ---- @@ -621,7 +621,7 @@ NULL #' @keywords data #' @examples #' df_construct_columns -#' importDataframe(df_construct_columns, format = "construct_columns", rmin =1, rmax = 5) +#' importDataframe(df_construct_columns, format = "construct_columns", rmin = 1, rmax = 5) NULL # # dataframe with columns as constructs diff --git a/R/export.r b/R/export.r index 5597c1e..01c31c2 100644 --- a/R/export.r +++ b/R/export.r @@ -356,7 +356,9 @@ add_one_sheet_with_grid <- function(x, wb, format = "wide", sheet = "grid") { jj_cols <- seq_len(ncol(df)) jj_cols_optional <- 5:7 j_preferred <- 5 - ii_end_construct <- rle(df$left_pole)$lengths %>% cumsum() %>% head(-1) + 1 + ii_end_construct <- rle(df$left_pole)$lengths %>% + cumsum() %>% + head(-1) + 1 style_header <- openxlsx::createStyle(textDecoration = "bold", fgFill = "grey90", border = "bottom") style_border_left <- openxlsx::createStyle(border = "left") diff --git a/R/import.r b/R/import.r index 29c559d..ab8cef0 100644 --- a/R/import.r +++ b/R/import.r @@ -1391,7 +1391,8 @@ importTxtInternal <- function(file, dir = NULL, min = NULL, max = NULL) { #' #' # To see the structure of the file, try opening it as follows. #' # (may not work on all systems) -#' \dontrun{ file.show(file) +#' \dontrun{ +#' file.show(file) #' } #' #' # Import more than one .txt file @@ -1419,7 +1420,7 @@ importTxt <- function(file, dir = NULL, min = NULL, max = NULL) { #' @param rmin,rmax Min and max of the rating scale. #' @return A reogrid object #' @noRd -df_wide_to_grid <- function(x, rmin = NULL, rmax = NULL ) { +df_wide_to_grid <- function(x, rmin = NULL, rmax = NULL) { if (!is.data.frame(x)) { stop("'x' must be a dataframe. Got '", class(x)[1], "' instead.") } @@ -1435,7 +1436,9 @@ df_wide_to_grid <- function(x, rmin = NULL, rmax = NULL ) { cols_elements <- seq_len(ne) + 1L rows_ratings <- seq_len(nc) - ratings <- x[rows_ratings, cols_elements] %>% as.matrix() %>% as.numeric() + ratings <- x[rows_ratings, cols_elements] %>% + as.matrix() %>% + as.numeric() if (any(is.na(ratings))) { stop("\nNA ratings are not allowed.", call. = FALSE) } @@ -1445,11 +1448,11 @@ df_wide_to_grid <- function(x, rmin = NULL, rmax = NULL ) { rmax <- rmax %||% suppressWarnings(as.numeric(trimws(nms[col_right_poles]))) # if unknown range, infer from data with warning - if (identical(rmin, numeric(0)) || is.na(rmin) || identical(rmax, numeric(0))|| is.na(rmax) ) { + if (identical(rmin, numeric(0)) || is.na(rmin) || identical(rmax, numeric(0)) || is.na(rmax)) { warning("The range of the rating scale was not supplied via args `rmin` and `rmax`.", - "\nI will set the min and max rating as scale range. This may be incorrect!", - "\nSee `?importExcel` for more information", - call. = FALSE + "\nI will set the min and max rating as scale range. This may be incorrect!", + "\nSee `?importExcel` for more information", + call. = FALSE ) rmin <- min(ratings, na.rm = TRUE) # infer rating range rmax <- max(ratings, na.rm = TRUE) @@ -1477,7 +1480,9 @@ df_long_to_wide <- function(df, rmin = NULL, rmax = NULL) { cols_missing <- cols_required[!cols_required %in% nms] if (length(cols_missing) > 0) { stop("\nMissing columns: ", paste(shQuote(cols_missing), collapse = ", "), - "\nSee `importDataframe()` for long format requirements.", call. = FALSE) + "\nSee `importDataframe()` for long format requirements.", + call. = FALSE + ) } rmin <- df[["rmin"]] %>% unique() @@ -1487,12 +1492,14 @@ df_long_to_wide <- function(df, rmin = NULL, rmax = NULL) { df_wide <- df %>% tidyr::pivot_wider(id_cols = c("left_pole", "right_pole"), names_from = "element", values_from = "rating") %>% dplyr::relocate(right_pole, .after = last_col()) - df_pref <- df %>% dplyr::count(left_pole, preferred_pole) %>% select(-n) + df_pref <- df %>% + dplyr::count(left_pole, preferred_pole) %>% + select(-n) df_wide <- df_wide %>% left_join(df_pref, by = join_by(left_pole)) if (!is.null(rmin) && !is.null(rmax)) { jj_poles <- c(1L, ncol(df_wide) - 1) - names(df_wide)[jj_poles] <- c(rmin, rmax) + names(df_wide)[jj_poles] <- c(rmin, rmax) } df_wide } @@ -1688,7 +1695,7 @@ importExcel <- function(file, sheet = 1, format = "wide", rmin = NULL, rmax = NU } -import_excel_wide <- function(file, sheet = 1,rmin = NULL, rmax = NULL) { +import_excel_wide <- function(file, sheet = 1, rmin = NULL, rmax = NULL) { x <- openxlsx::read.xlsx(file, sheet = sheet, colNames = FALSE) # colNames = FALSE as spaces are treated incorrectly names(x) <- x[1L, ] x <- x[-1L, ] @@ -1696,7 +1703,7 @@ import_excel_wide <- function(file, sheet = 1,rmin = NULL, rmax = NULL) { } -import_excel_long <- function(file, sheet = 1,rmin = NULL, rmax = NULL) { +import_excel_long <- function(file, sheet = 1, rmin = NULL, rmax = NULL) { x <- openxlsx::read.xlsx(file, sheet = sheet, colNames = TRUE) importDataframe(x, format = "long", rmin = rmin, rmax = rmax) } diff --git a/R/utils.r b/R/utils.r index 239ef52..1b71c01 100644 --- a/R/utils.r +++ b/R/utils.r @@ -1023,7 +1023,7 @@ list_to_dataframe <- function(l) { } -`%||%` <- function(a, b){ +`%||%` <- function(a, b) { if (!is.null(a)) { a } else { diff --git a/man/df_construct_columns.Rd b/man/df_construct_columns.Rd index 0688c64..9bc8101 100644 --- a/man/df_construct_columns.Rd +++ b/man/df_construct_columns.Rd @@ -22,7 +22,7 @@ min and max of the rating scale should be passed explicitly via the args \code{r } \examples{ df_construct_columns -importDataframe(df_construct_columns, format = "construct_columns", rmin =1, rmax = 5) +importDataframe(df_construct_columns, format = "construct_columns", rmin = 1, rmax = 5) } \seealso{ \code{\link[=importDataframe]{importDataframe()}} diff --git a/man/importTxt.Rd b/man/importTxt.Rd index a0a5619..8fc6ff2 100644 --- a/man/importTxt.Rd +++ b/man/importTxt.Rd @@ -92,7 +92,8 @@ rg <- importTxt(file) # To see the structure of the file, try opening it as follows. # (may not work on all systems) -\dontrun{ file.show(file) +\dontrun{ +file.show(file) } # Import more than one .txt file diff --git a/tests/testthat/test-calc.R b/tests/testthat/test-calc.R index 89b0a7a..e55971e 100644 --- a/tests/testthat/test-calc.R +++ b/tests/testthat/test-calc.R @@ -1,4 +1,3 @@ - # test for issues #22 and #31 (constructs were missing after align) test_that("align()", { sorted_poles <- function(x) { diff --git a/tests/testthat/test-gridlist.R b/tests/testthat/test-gridlist.R index 4c9c0e0..91a31f0 100644 --- a/tests/testthat/test-gridlist.R +++ b/tests/testthat/test-gridlist.R @@ -1,5 +1,4 @@ test_that("gridlist works correctly", { - l <- list(boeker, feixas2004) expect_true(is_list_of_repgrids(l)) l2 <- append(l, "hello") diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 7745f7f..428629e 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -36,7 +36,6 @@ test_that("get_names_na*", { l2 <- list(a = 1, b = 2, 3) expect_equal(get_names_na(l2), c("a", "b", NA)) - l3 <- setNames(list(1,2,3), c("x", "", "z")) + l3 <- setNames(list(1, 2, 3), c("x", "", "z")) expect_equal(get_names_na(l3), c("x", NA, "z")) }) - diff --git a/tests/testthat/test_biplot.R b/tests/testthat/test_biplot.R index 4da8973..f468b3a 100644 --- a/tests/testthat/test_biplot.R +++ b/tests/testthat/test_biplot.R @@ -3,7 +3,6 @@ library(vdiffr) test_that("biplots work", { - create_biplot2d <- function() { set.seed(0) biplot2d(boeker) From 14add25a2bf0eda4153a35913b9fd4ec526967a3 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 23:08:34 +0200 Subject: [PATCH 21/28] update vignettes --- vignettes/web/images/excel.png | Bin 27810 -> 0 bytes vignettes/web/images/excel2.png | Bin 68614 -> 0 bytes vignettes/web/images/excel3.png | Bin 0 -> 201463 bytes vignettes/web/images/sample.xlsx | Bin 0 -> 10417 bytes vignettes/web/loading.Rmd | 101 +++++++++++++++++-------------- 5 files changed, 57 insertions(+), 44 deletions(-) delete mode 100644 vignettes/web/images/excel.png delete mode 100644 vignettes/web/images/excel2.png create mode 100644 vignettes/web/images/excel3.png create mode 100644 vignettes/web/images/sample.xlsx diff --git a/vignettes/web/images/excel.png b/vignettes/web/images/excel.png deleted file mode 100644 index 3e4dc3739b77f5b00309a721600b9d40a6dffac6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27810 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 diff --git a/vignettes/web/images/excel2.png b/vignettes/web/images/excel2.png deleted file mode 100644 index 03557f992de686a7034b6c8848d5aa9cc85f977c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68614 zcmbSygLf}I)NXB@+O}=mwr%%U_tZV@scpBXwr$(CZTt59)_3n8aM!HKB-yi)y?1t! zdDc7$Q6JVfsH0Fbg3$At0dI7}yUZ@SifF ziKMa|5Rex+5RiW`5YXFCmH!D4kSik)(3v3+5O*pN5QbxBn-cGj0K!;CLKNuxzbm)1 zIN_%T+EG#q00e|i_TLRGrA&JBQwixJB_{^C3yJWHiD@L+PWPupASqEHRgblcEDI0a z!A1Y=R(J2&DzED+_(-M}MO*GX5fIWuLF7Kj073s>$jF3Xk{|)7UJ6j1?!pX3t@ju1Zv(TxcLuAlL*ctMa}B(R7y z*TI`8DKeHa1UGs_-uas$hDi^mHM`8Rt8wkhe+9{y{q0N_FdK#fcQ?{t%!_=uk`9ru zhK|xn#c)GtqPGLN^@;_vlF|0|6%qvXZ>$YPCf0UPqJdc0=KdLL5|LR>M6%DPr`@~( z#YQcW!Muwkj>)R}b-W5oR%ss}9|I^?2Rzx}{9H zj%N6jcoAQ1cwkyazlgbYnoog~y?017gJ`aII5myOoA`R}5HcsF&)jTogMU;DYHp6+ z4^qNt543XUuUKw{0RurrMFsLMH+JF1vAKoiDD+Ibkn>&gN9d9i?qb*G{x}H%Q|nDi zPzV?X2eo8`T;rq(C&jhQYi-1l({S>tA02lqKv1N>tKlbNzcnMQK^l#!&fKAOVA={Xk&Ku)p$t1ev-XFD1tVrNaiK_dW@{$e z(JVg6$V8#sqdK~69PCo=5|f>w7608Z<%s5j9g+q;Ldn1&X8U@(FJt2zl?2sT4z}f~ zFCxu>JCg#xHG5ZoT<{IWV7!OTJb>Ex_v;4U$Jcf}CFKMK^0hd6C8V0^RvP z(s3D1Y_Z9*o#5-7{?+Y_zOT)O2U_lsU0*Zd{7vDhpQNeET<3g+4q49OeE9s{eb?S8#}rPi_4(?( zKv6d;OKY-p$1aYq8rYTMp$W?Ko-|;h#5_bWZBWI9Ba z=>nu5$Q4n%*2|SUR_Vl%Q&^V+2v{-}qSg@%8MIl&)d6StJt@+XRn`UQ+*spf>1PIy zEG}KR=85GI=F|P=_6A2$=uWI_oMw9OXW#<7Av(gX+`K))J=_I?(N5ux(NK@ppt1OD z!>H4r5|#xqUf!OtF#2aL|GgiiL9APHfE?$zK8Fw-1x;`>~DddQurV;m=3+)N_0+iCUgAcV}G&s5}V?s5-|4&E3}bgj6-B z>OJ^Z(-MDnri*_k&QSjq=8m7iAdP3vut zJN$_&9ePn8`O6%ALQ7VMGx`^M*^q*%W-Uf-=s5F?)Ri#ee2o)$MCYbu8(3w?lw)uo z@B__Lk<&-}0Eb(R+fZv@CrtyTX<%W_S4`CgbmY`?Y=S4J$s)(=?^}o>)eBfS-&Cg_ zcO+s=XHZ zV>$8&j=GeqcyqxQ;Bf=NIx|dhVoZi2^L)n}Qd`apk_oGSDj06r-_j|i?T$jBKqGq2 z4ZvRkbdw5?7S$-5=v%&$3p5F0uaqGi zwsn7`pV`ucFz!FDK++2HVcx~Fq(}IA<4Hu05gSo*Ze;VVxi=@f0|krjkg_Ncp`H?= zhek%m>3VGDgn?_fe1<37i0w-&tLnGWf))7 z!FJG0Ep9cq(V+f$T7=canLLin$?lD`noo6GQTjN!P?4(e&6-|%eYSKym}17{(j*TJ z&EF#qA1mYBNhNV~YpQRmLi6!|;zd-&QIf-d%3{u51PGXGi9m+02A7pl3RB=lF)Grz z=Dr92q7E-JX3m&x=eWIsgdHtQ7uG7O8@{hL{6*}hoUe&@aEPI-swt}Ei@-kKGnow` zqOS_Ob)kEAe?K}s-fOpBNpW+bxW&g%54LNxHmhQ(`3X!gu^F7V;>fva+OoMKYuuCk z4(UY_uPWQZ0*G&$oF)-qfIJ3jKJGNb{jRE&>2%b{EZ2WR7=%Kl>nSGa5V3gT&vgD! zI>-Q4jg<2IeRFi&@!k778W(_RzKOYD`V8za5fV`C23+0!MD2!UzQ6IUq@y|NSs

`lS#af&$6_2s**_3FAgyWUtuMYilu@g(>W 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%0DbUcb|Ray=I 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 P00000NkvXXu0mjffjc!8 diff --git a/vignettes/web/images/excel3.png b/vignettes/web/images/excel3.png new file mode 100644 index 0000000000000000000000000000000000000000..24e1053c15a2993c2cb38e25a2ecbf034691ca5b GIT binary patch literal 201463 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 z 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 BfDf@u;usCl_x@&$N!lK^Al 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 literal 0 HcmV?d00001 diff --git a/vignettes/web/images/sample.xlsx b/vignettes/web/images/sample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5e4643d8cb08e1ae1f7fe48225f5f9c03de35984 GIT binary patch literal 10417 zcmeHN1y@|jwr<>^aR{y8zPA>`0RR9Q-~*kNttA8i0E7VmFahw8n!>g=PR2G) zx=QYL#*W$yZq`<$xzLa_*#JoJ`u|=3#XC@z*dg1+gdB1z{#iJQ)}qG#HGKJ^emgof zGchUU$uoMHTuy?;#Z41Kp`tRO!~C}dcTa5%F4Q&JhSl`YQ=`dNT9In7D%|g)I%#m?2#9jGVxMz5hfkVIN#Q%*yYQ#<6HFdK^DkE&2)Y)PLVuTNTYkG8PeOz^ zD9x;98S^Tr!>v%b`J%pq`7}uqvo^qrOvnozMgJ^wJ&U1CAVU*(_YF6Vwz4_G;DC%U zHqAI35Yf_aE`_}O4Mpw44*zCWKwP0QFO#@uE9Fub`o1re+}IF$ymSm%Zwmxr(~(5& zSR)R^lqND8ejwES)X92mXTQ4)J&PT>Y}4+2u`OtJl<$jI>H z{y%R17ZdU?k6sopBljCO??d~qr~1AK7JBQXmwF}lmyFd&k2D_&jO*u zd|Q0(2N#!lqYnDXt~S`pA~3LcC_t{|A@6VPo#9?mJ0y$Rm#ufByG&nBU!{sky3@F{ z#JntRD9Vul#_LUx=i)VLo`# z%VzW|kh5WYXBiXgqsqSY)u?6rI+W?&{R*M0wEt`%AcCZ51?;Z=Ns_cBIUX-40H6=- z*U-Q_<7UO^YU^NWU~6mn!-}^SIcG$ z!xq&D`j*q2Q^Mk*E>`eR7q}+)+Clk~!Spz&&eULX2C`|`heFO{2}yuVUSqGw8s1aP z`ueF43m}XiP5$}q7r&?XHMBI{xVO;8{u}S_Dq5!8vzF?Ek-t7j5gJX-T^J5YY!tuY zjo17nr8Ok?Kq~b%&BN#xB_K{m4Su22Lf0OJC>46p)2OLnaU$UD+{JlPFVcc99p4jE zB*>Oq&%1uv0kp4Em-D{&D!M*@PGkq#6F7Cz;6&K6gxt%cQ-a90$+J~;jk_6x&D1-o zkLmH6HDVZ7pktCZ1&G9>ZeYxeP(~`wiX;aw0m=BGsT&_}-j)WXo<^R)B#$WZiN+n_ zeO;?=C{}t1@+HD~b+<4=UnrsmZnh&IN;JQyY&PGVing;wil6~uzka~R3&gPC>UWmt z0(Nv+(uA~Btj`?_=jo)hw22;2;eGpLIBEC@bs5r(-{fnEYm}`ev6&79xsVoWziz*# zpYOiJWP=E&>}z~u=T}DgHEetI{2fnE4V&YIYBl%$Hry%MD)9#srOWZWCcaSTqCT%S z&pE9Vjw@x4S@(6Xf{Rw)+b6=d*WcKACb-)8CYT?*S{nE#u3u^{t!@``_stH_@h=N} z7~Ay4nP1&Rzw)J?B1Wv}6D+u*Nr*TF)9{}}jfYD-f(BDq08G|r0C)&6QGau2f2Hdm z&J6+_c!JmdcVA`kLl)gk$ZxKL9|I>^?OD9#L+ni^6jH3yef;baIi(HYG`+V@Efu&2 z+GB01nZ-M=iQhFZ`nr~XrzCl1iftr;7*OV7Y-kB{+A}ml5!P-dWtB+<0|hg;JFD8P zY7w_tsF%hcR%8$e*|lVwkGvosN@mYD&sm&t8f&<3IiJUGAmflwfc9mKom5~FD^$T> zAhDh_JSS%K$+Ee`f{l;oVIpoD35Vruycb5qzm;0$O!Ijh`j+wCNZJ+Qm{7u<+Thob zWV~v2{MHNsSmAEWzGCbxPW7NhT})BK(kx^SmjJH1WCn+N3mRmPm#cGq!(%nfwoe`X zHFLWH|EfdTLnxfi;Ed(fGXMY&yyACb?`URh?BvM!b71~q^)nLGW73(hf>&uT1=M^@ zb*Zys-zMTueOAt77>jO%ro~fSoY%N)yB12uf06Vo3VIH2)V1PxbAMA1WCXVWKaI_1 z=PjANS%R_Ll)c)TJQ{>ysIK}+#aVuw0`Hdd?z?`Is)yk-fK=>wY5>Q~RpT!Hil0%h zGN04;d=(9rh)R#+R2`^N(KxG?@oPmnmWc^Wve|1UC2b^Bxo}%5rz_}*ah8b7bkT1+ zLJ9Z88Acv8$3zuIF=0t&!Flbm>-nwbQT%;(uR2$y#l0F{lHHbP z#+)j*(WuBz8J7@bzhR_*egv(~l`7DuuV#YgyJw|=u(YnPA|k9k?jFk+=;u+hkC%N4 zd9@>xr3Uiw$7z6JL!i0IPxM;1nrkNQRYG&ueo==XBz4~-hQx{pi_}{_*8#Zz%8r1G zydRsuYBt-`CR)8>JlRe;8%rxo@ej7}4IAVz3;%#UWwp4#Xz_&5-SmkwZ9@|I?O^F9 zCSEjtufmdD)q2SrYW{avUFzNN)m?KZWBub%x#KYbOgTZeQOf5AE;Ct)Zbo8MAY9|E z0`sH7Cv+22GLR}66)h78OZe-P!)0&v6F5|Uditq587a#)>92vox-iGelPVp0n9p%Q zSdWe7`QqLHk*cM1N*0xcR&Q7QArsVhtf>Tx2)hI>yTeBe-47LqsOpYp9A6)AV(N9% z+ua_dE~XZBOL;brQLjQD9tr5uTrR&e9^QgHtDiEoL*wSV%MDM6YB{9tt`Dih9%f~Z z>iaAaw9^U3gdVa}?B8%JzmBvjfp?GeDoJsC!>ml#kel(6yrM`P9ks^Kl3lwQe}wfj z*Lv&7$%`H`xv!eVe8w~8vpX(WmxNCJ-a_H+7@C#V8UE>^S#3T>y2K~Pebcjhi$@;# z-q$9opW2*ZJK87h0lO0w^R6+yi>`}x5?#vXm5N%GPuAW~G`t?yvTitEd=0f4@k9!H zNRg*Urluca2j5Z`2nP=q!)rxqX`BxhOQ1)UZqn&b>+={d`Qes!nY%kL30=n-u;h0v z8MVHI(gfw*c&qV_yYBORRqyZ6rbA+e-%hja5JDE>OVX$!x6{Ibn1PX?bk^?*JM1)f z*Ip9Tj@?iwhBG-siH{2xEJ~C{7INHP;K5noN(Qfw#YaU^PY^L^m<~g6)v$2`G+PN_ z1aBGuBZs<4ZFUxNa29xeuH!;2S4jxs@?k&(eOv4boU<>4>HE6%2E%{TjT{&_2S#{m zA#dnZ!blwx(n9t{hmKpYOHf8L3amFw25iPY1yMrw*%ROf#y&|S?HB+{nt*|BpJxNG z{fF)Glw>e=zPsb=@!7j=`aWCz|bk~`mE__W3tI}rq`#h zo=Yss0O@@~L++4-)|Y7`vgcpTwPaMp;@t(@BgBZczpV(gu|I&r-QRWHDf$y?Clj)W zFV#8RxC$1e!esC}hlH(B2<+Np2BOq_sHo4FZU^`L zzPEpS{o)-$N$U{*+JKa}(lC*jvwS5To&*_#4wvs@ruCtT;o^gwCKIm8_C8wV9$X@t zR@Z%?Gs1<%rBP#2SkVK)zqxzao|1wFIB?=h{-eP3(^NZ|8Cx4O{=EOR(nlI2F$DG4 zZE*chuZOi~hW9-6xyB1$U7dKWCuwhqOC*NqjM}|cXr{%2K-`^@@`p5^kn&&gpb3XH z^Mh^Niec8Hka-H@br4Nk4-ap7d>wD#%E&r(%J;a_(s#WQ>v)||nv#P=PPr{Hi*)jx zn0z2|%)I)@Lyme=a#2`e-6$GgPJC7qbKl$HbTj5;0}4AXg)~-f3*y8hPGMiL?xiVH z%;~C~&dQ13j)DumX6~I}%K^2Dt-8Cv8KyK+uB>L`^*9 z*(RG(x0XB^fwDCuGxQIziTjnO{F@D|&p7BlLl}SWMQz;;eUKgLB#;lWJy|=<)1f6) zcY_MYlNoiL7*T0n9-h$b52z7-{&~{swp<^TQ67l0xc5bo&Mo(Jc6Hm_9U~0n`2!OLcJH}bDM{WJzqq(2El!j(`7!0{GovKB<%9@j{A;{Tq}e5?3^i2Zas~0qseA_@dc@9)u6LbM z@xb73w)YvpzDaM5cjbDaVMgX~yrTv~%*oF@3-9wZ$YsYX}Hhc;~!CrrojbOKfFInzk3A!fNHqKQp z{SqK5Zu+#F&0YJ#F(7#Dy@1^5MMo2H{f6tl>(zErm!*J|ry0_&GD5ufd%!c6EEbSbexmh?d>_WOhX`j`7x97DtPU0ulI+HE&v~m)J zO7;t8JjQ3G${Q$0-l5F74fg7nN*eE((2`8ub4;Nu=FeL!1IMdh zk-beDrhe-fYi13rD=c)H(L#bl1Q!8PX|tb>e&M$;LwmLowPxLN$bNuNF&7s|>|ODY z*yypTeVlQ9uf9-lHw&$~M~)Q<%koRQKwv_Dv@z6%uWF(AOmMGb3o*E_bKo z>t)}UYc>amvg-;FA2@nU*s<6&j?vaFGes)4VUrVCVWh^X%Dw_|GDA%`k3Ep)UWE*C z2Cv24E+f@Y5jGDe_N&}4eoR&pXYXbiq_e4(-N{OMNe;}jpPd|QLxD?9p^T3^Z2$6* zACGhyaF-tkRk^4`9RZVCT)iqqvG8S{{^NH#bxvRQ4O_ICcrTa}{)nCTW`iml%ppL_ zTFB#Nt|U7zpi#vKMNYIulWOwE3grUcJIzq7H~hVHQFb~CgY&$B=>gUGh9@8nn&s^= zWY}f)b*Ez5BcAumv$Gb~jk)|T;koAd*xDS+^WVCZZ!k)8!!^pPm%RCQT{s3%A*a=; zS6Zhxx;PqA$-^OhyJ@LMQ)#t;b>-?ClLS!+^eB)ctsL35bRQ&A0*F*Juj&L0+NevM_?tz*=tX@iNl3(5rQnF?AS2X2)?k(WLmES)G)-?Z6|a)NvRs z=EBC0%8!GOv8<{*yJoQl#`)9Gn;MvA?9qie%ZC#B&q;HHH8#N`Gr19D5q6tZ9YPig_2d2ExLn&*3YNOTjrjrF$1crQ+EG zpZw*$>6a~{c{q{J`~{9ev!M8}dju)&cJz@81+6lDZ}fUyTYbV_!Rfe~@K!inI15j^ zt$IBGgQ6=*#zlO$*8C~_RX7n3^ce}2V7s!_i$l9i@|R04Uj|ljA$!W#rf;t75;rle zWeX5S_eE8GAp}&MTt7?FY2zqjTg>y}L>0ZvL0kKLuhpR$IojArzxL&<>6+qSbFx5B zH^?6axI+{G0Q~uplQ}xMTNyk4NW_L!7i|_ff!?}$Pl9XBkJ?;|BJy+1(+Xr>F>+Lzjt<+Q7H`SWHaN;TcO^>4`TEBR8|O$; zU%$A$V{m=nZ;l*CwJ!MuE7L4+#i;EmnQf~y(eX(1yqKPMC53DNuMIebEqm|Dcf3(|nS>%Im0#G-flJiV!0&T9SWJ-5d? zFJ)W^i$Ff&h=rGiM4aWsQBHZfbLeH`C2x}&0a|j(*tC1^om5u_DSCpS`^SXODbV1u zZdMLV$%8)>Tn`tZ8B64UG|vzs%9lVls&I69&?!MW}pFide4B5N;`(eJBr2cH+ooJZtTGmi7KRWi#HjE=bB^5@0uCJ-GUE^6P8gKj-2 zae#@TFYXbkI2B^v?3;>Gd9+|X_SImtwbnS? z9AZqrz&4wd1_&gy)x>gL;V0)Vo*+~V%@;2d;lGmRC-w2u03~F&xYm8L-Ha<+?k7C37rbHV_SI;h}bk+pJm;C_XXeV`_^d0IJ8Z9%+XC;B|IN$SyU}_9}g7 z`idHDiE4#z*-ntc726tQgQa5&TJ#Er@_JZ3GJb?QJwFkKoce+`ixN89Oq@Z~zbb18 z94VfhJUvm$=G$#WH1NW{nH#~KbL~o@TQ>e2w#0iLXiaEilgpcCAM@eHr|-k*wJv0` zS1pIM{ODFnDYNj!TX76068la9)^!YNqdCY^3Pq zU~XgjldWEptCC$zSg>cF9j@?=uKOIBieHX|&Jez72zf5Ro)=OV?=7bL$IjIpRqu+e z-N|D5+;XIO`J)ZaC)>P2q0-}-rR4#AdpN#45tj)2a;3n7ME~IbT5jViBorvYZ7D2O zh_`FnEA+}gPJh#+N&$yjw(~r%4+}d^?Od>2iD4g$AH5^g~f?m-eBK@y%u5?&s9iW)485b(Pm z_sw7&%CFPbn)NW7+#F&}CeHc}t~C9#jyWZ!iAW3H$ZTkE_x!hwG}N~;6gJa0xA|f6 zjHZ@lgP4FYYo3^^IjNrYRR_12dI>Wi#%#3l#HQHSWQlm*o~83t9v;G-a9sG@tV(@j z_Ie~f?;fx$Ub@0ClPpbLtt(9~mbSW6;;0g6@JM&ee%q!XN5dSgp%Ypy7>gJD0YVWZtEJ&1$20BU) zxP=)){&QlKs54^}e!Dtb$Z0Iyzt2q75QumH8#e|N{0f3QWV~F zjX--yt2K#1i~^)uM_J5B`bGbb9OtOpJu=pm&OVkPHAPUNX1h7zSQWGwmorv1Aj!H^3C{Wo&jvk3`~{Z6y@NaTYGO@m69dQQfIiIFE_rOhn+FUXPwt8ns0= zL&#XxTK)E=k9|;RUTj}*xo9irAG$332iar`^}RM{Uq(rAP)u&Mct7<$a9H?~%Ds4$$&i-d zz(*hRW9h?P&Ab0uBK)=2E=SN1_a3Z##9;FX{HyZm+u8k3_rOZ``;`&jA-l;03^}De z<`HRCEIdLif7u6*twMBagouPcW_{{SUzTpeO(FQKnqMiYyLlc#d3;%p%u? zjB4T8vq08lC|YIdC^Fee+1?TdoQgbe8`4>z0v~XT0Rnf z8&rBIOXq3Oin{QI3DfbNu;ws`ON&tN`R`vLP3fn$`uzE_ny{(dCAO-o7y>c z6AQ86Kz%?H%w&wMv6fIdw}zA6ivr|jUE;OIeh_R99Ic3HJgYxml`TO6*%iIQ7gckl zXuHFw7NDR)e6y%Ad?8%Hr@P`^VJNu5sFn`#uFe;`y>W1#D^;i`p3hypxN2t-is5YD z8bovID!uvOIyy90OHHW8De9}`)*0%8S&7ndC?XeOp`8v*<=bh$(HGFPtxvt0PG^bf zBHw!Dg>@_AMmVcI#%OXAlhNj)pm=Wm>CzYcT7I*n5Rmj>zy9yXyZ(52e~kZf*h^mO z?*jgQ_T&%XkMSdzA%8iE@+l41bmL zYoF*(Ng(9^{E2^bjeeE#YYFpDDf$>crTkjZ{8hlOsnMSTB*6`=za>h)LVpd{{)B!d z`VIPP@b;^OU*nWNC2*7cl<>Ex %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{Loading} @@ -19,40 +20,46 @@ settings(show.scale = FALSE, show.meta = FALSE) The `OpenRepGrid` R package is able to read files from different other grid programs as well as standard formats (i. e. `.txt`, `.xlsx`). All import functions follow the same naming scheme. They start with the word `import` followed by the program the file is imported from, e.g. `Gridstat`. Hence the function to import a Gridstat file is called `importGridstat`. - ### Loading OpenRepGrid files - #### Microsoft Excel files -You can define a grid file using Microsoft Excel. The `.xlsx` file has to be in a fixed format. See an example of a correct file below. The first row contains the minimum of the rating scale (red), the names of the elements (green) and the maximum of the rating scale (red). Below, every row contains the left construct pole (blue), the ratings (black) and the right construct pole (blue). - -![](images/excel2.png) +You can define a grid file using Microsoft Excel. The `.xlsx` file has to be in a fixed format. See an example of a correct file below. The first row contains the minimum of the rating scale (red), the names of the elements (green) and the maximum of the rating scale (red). Below, every row contains the left construct pole (blue), the ratings (black) and the right construct pole (blue). The rightmost columns (purple) is optional and contains the preferred pole. Allowed values are +`left`, `right`, `none` or an empty cell. +reference diagram -To load an `.xlsx` file and save it into the object `x` type the following code to the R console (assuming you have a file called `sample.xlsx` exists). +To load an `.xlsx` file and save it into the object `x` type the following code to the R console (assuming your file is +named `sample.xlsx`). ```{r eval=FALSE} x <- importExcel("sample.xlsx") ``` -The `OpenRepGrid` package comes with an example Excel file. If you have Excel installed, you should be able to open it by typing +The `OpenRepGrid` package comes with an example Excel file. If you have Excel installed, you should be able to open it +by typing ```{r eval=FALSE} file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") -file.show(file) # may not work on all systems +browseURL(file) # may not work on all systems ``` +#### .txt files +If you do not have a grid program at hand you can define a grid using a standard text editor and by saving it as a +`.txt` file. The `.txt` file has to be in a fixed format. There are three mandatory blocks each starting and ending +with a predefined tag in uppercase letters. The first block starts with `ELEMENTS` and ends with` ⁠END ELEMENTS`⁠. It +contains one element per line. The other mandatory blocks are `CONSTRUCTS` and `RATINGS` (see below). In the block +containing the constructs the left and right pole are separated by a colon (:). To define missing values use NA. The +block `PREFERRED` is optional. Each line indicated the preferred construct pole. Allowed values are left, right, none (no +pole preferred), and NA (unknown). The block RANGE is optional but recommended. It gives the rating scale range defined +by two numbers. The order of the blocks is arbitrary. All text outside the blocks is discarded and can be used for +comments. -#### .txt files + ---------------- sample .txt file ------------------- -If you do not have a grid program at hand you can define a grid using a standard text editor and by saving it as a `.txt` file. The `.txt` file has to be in a fixed format. There are three mandatory blocks each starting and ending with a predefined tag in uppercase letters. The first block starts with `ELEMENTS` and ends with `END ELEMENTS` and contains one element in each line. The other mandatory blocks contain the constructs and ratings (see below). In the block containing the constructs the left and right pole are separated by a colon (`:`). The order of the blocks is arbitrary. All text not contained within the blocks is discarded and can thus be used for comments. + Note: anything outside the tag pairs is discarded - ------------ example.txt file --------------- - - anything not contained within the tags will be discarded - ELEMENTS element 1 element 2 @@ -66,6 +73,13 @@ If you do not have a grid program at hand you can define a grid using a standard left pole 4 : right pole 4 END CONSTRUCTS + PREFERRED + left + left + right + none + END PREFERRED + RATINGS 1 3 2 4 1 1 @@ -76,7 +90,8 @@ If you do not have a grid program at hand you can define a grid using a standard RANGE 1 4 END RANGE - ---------------- end of file ---------------- + + ------------------ end of file ------------------ To load the `.txt` file and save it into the object `x` type the following code to the R console. @@ -84,89 +99,87 @@ To load the `.txt` file and save it into the object `x` type the following code x <- importTxt("example.txt") ``` -You have to make sure, that the file exists in the current working directory. If not you either have to specify the whole path to the file or you must change the R working directory. +You have to make sure, that the file exists in the current working directory. If not you either have to specify the whole path to the file or you must change the R working directory. A sample `.txt` file is also contained in the package. The `OpenRepGrid` package comes with an sample `.txt` file. You can load it as follows. ```{r eval=FALSE} -x <- importTxt("my_folder/example.txt") # whole path to file or -getwd() # show current working directory -setwd("my_folder") # change working directory to the folder markheckmann/data -x <- importTxt("example.txt") # load file that is in the current working directory +file <- system.file("extdata", "grid_01.txt", package = "OpenRepGrid") +x <- importTxt(file) ``` -The `OpenRepGrid` package comes with an sample `.txt` file. You can load it as follows. +To open the sample `.txt` file try: ```{r eval=FALSE} -file <- system.file("extdata", "grid_01.txt", package = "OpenRepGrid") -x <- importTxt(file) +browseURL(file) # may not work on all systems ``` -To open the sample `.txt` file try: +#### Convert a dataframe into a grid + +Sometimes, you may want to convert data you loaded elsewhere into a repgrid. A dataframe is a central R data structure and +can easily be converted into a `repgrid` object using `importDataframe`. Please have a look at the docs for details (`?importDataframe`). The +package comes with several sample dataframes, for example, `df_element_columns`. You can import it as follows. ```{r eval=FALSE} -file.show(file) # may not work on all systems +importDataframe(df_element_columns) ``` ### Import files from other grid programs -To import from other grid programs works the same as importing a `.txt` file. Either you specify the file name if it resides in the current R working directory, you supply the whole file path if it is not in the current directory or you do not supply any argumnets and and interactive file selection dialog window will open. +To import from other grid programs works the same as importing a `.txt` file. Either you specify the file name if it resides in the current R working directory, you supply the whole file path if it is not in the current directory. #### Gridcor ```{r eval=FALSE} -x <- importGridcor("gridcor.dat") # file in current R working directory or -x <- importGridcor("markheckmann/data/gridcor.dat") # whole file path or -x <- importGridcor() # open file selection dialog +x <- importGridcor("gridcor.dat") # file in current R working directory ``` #### Gridstat ```{r eval=FALSE} -x <- importGridstat("gridstat.dat") # file in current R working directory or -x <- importGridstat("markheckmann/data/gridstat.dat") # whole file path or -x <- importGridstat() # open file selection dialog +x <- importGridstat("gridstat.dat") # file in current R working directory ``` #### GridSuite ```{r eval=FALSE} -x <- importGridsuite("gridsuite.xml") # file in current R working directory or -x <- importGridsuite("markheckmann/data/gridsuite.xml") # whole file path or -x <- importGridsuite() # open file selection dialog +x <- importGridsuite("gridsuite.xml") # file in current R working directory ``` #### sci:vesco ```{r eval=FALSE} -x <- importScivesco("scivesco.scires") # file in current R working directory or -x <- importScivesco("markheckmann/data/scivesco.scires") # whole file path or -x <- importScivesco() # open file selection dialog +x <- importScivesco("scivesco.scires") # file in current R working directory ``` ### Saving grids -`OpenRepGrid` can currently save grids in two formats. Either as a `.txt` file or as an R data object. +`OpenRepGrid` can currently save grids in several formats. Either as a `.txt` file or as an R data object. + +#### Excel file + +The most convenient format is probably an Excel file. You can save one or more grids to Excel using `saveAsExcel`. + +```{r eval=FALSE} +saveAsExcel(boeker, file = "boeker.xlsx") # save it to the file "boeker.xlsx" +``` #### .txt file -To save a grid as a `.txt` file use the function `saveAsTxt`. It will save the grid as a .txt file in format used by `OpenRepGrid`. This file format can also easily be edited by hand (see `importTxt` for a description). The function will open an interactive dialog box to let the user enter a filename if no file argument is supplied in the function call. Let's suppose we want to strore the `boeker` grid. +To save a grid as a `.txt` file use the function `saveAsTxt`. It will save the grid as a .txt file in format used by `OpenRepGrid`. This file format can also easily be edited by hand (see `importTxt` for a description). ```{r eval=FALSE} saveAsTxt(boeker, "boeker.txt") # save it to the file "boeker.txt" -saveAsTxt(boeker) # open a dialog box to enter the file name interactively ``` #### R data object -Another option is to save the grid as an `RData` object. This is done by using the function save. +Another option is to save the grid as an `RData` object. This is done by using the function `save`. ```{r eval=FALSE} save(boeker, file = "boeker.RData") # save it to the file "boeker.RData" ``` - -In future versions of OpenRepGrid will also support the `.xml` format once a community standard has been agreed upon. From 427fa1203874676127858da2d69a840ec2c36d97 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 23:11:20 +0200 Subject: [PATCH 22/28] set version to 0.1.18 --- DESCRIPTION | 2 +- NEWS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 378ef20..992bd58 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Description: Analyze repertory grids, a qualitative-quantitative to quantitatively analyze and visualize repertory grid data (e.g. 'Fransella', 'Bell', & 'Bannister', 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. -Version: 0.1.18.9010 +Version: 0.1.18 Date: 2025-07-07 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid diff --git a/NEWS.md b/NEWS.md index 3af40db..d17583e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# OpenRepGrid 0.1.18 (dev version) +# OpenRepGrid 0.1.18 * `saveAsExcel` can export a list of grids now (#67) * `saveAsWorksheet` to add grid as anew to an in `openxlsx` `Workbook` object. From c4f945ebf142bb692acebdc7afaa5a0c12054d92 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 23:27:02 +0200 Subject: [PATCH 23/28] update pkgdown --- R/repgrid-plots.r | 4 ++-- _pkgdown.yml | 7 ++++++- man/biplot2d.Rd | 3 +-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/R/repgrid-plots.r b/R/repgrid-plots.r index 2dd45d0..84e517c 100644 --- a/R/repgrid-plots.r +++ b/R/repgrid-plots.r @@ -1486,9 +1486,9 @@ addVarianceExplainedToBiplot2d <- function(x, dim = c(1, 2, 3), var.cex = .7, #' - Interactive 3D biplots: [biplot3d()], [biplotEsa3d()], [biplotSlater3d()]; #' - Function to set view in 3D: [home()] #' -#' @examples \dontrun{ -#' +#' @examples #' biplot2d(boeker) # biplot of boeker data +#' \dontrun{ #' biplot2d(boeker, c.lines = T) # add construct lines #' biplot2d(boeker, center = 2) # with column centering #' biplot2d(boeker, center = 4) # midpoint centering diff --git a/_pkgdown.yml b/_pkgdown.yml index d9394c5..29eb6a6 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -67,6 +67,7 @@ reference: - constructRmsCor - constructs - preferredPoles + - preferredPolesByIdeal - alignByIdeal - alignByLoadings - alignByPreferredPole @@ -111,6 +112,9 @@ reference: - data-raeithel - data-slater1977a - data-slater1977b + - df_element_columns + - df_construct_columns + - df_long - title: Settings contents: @@ -122,11 +126,13 @@ reference: contents: - importExcel - importTxt + - importDataframe - importGridcor - importGridstat - importGridsuite - importScivesco - saveAsExcel + - saveAsWorksheet - saveAsTxt - title: Plots @@ -172,4 +178,3 @@ reference: - "[,repgrid-method" - "[<-,repgrid-method" - cbind.repgrid - diff --git a/man/biplot2d.Rd b/man/biplot2d.Rd index 09c3b85..c3f610c 100644 --- a/man/biplot2d.Rd +++ b/man/biplot2d.Rd @@ -282,9 +282,8 @@ Note that the grid matrix values are only recovered and the projection property is only given if \eqn{g + h = 1}{g + h = 1} } \examples{ -\dontrun{ - biplot2d(boeker) # biplot of boeker data +\dontrun{ biplot2d(boeker, c.lines = T) # add construct lines biplot2d(boeker, center = 2) # with column centering biplot2d(boeker, center = 4) # midpoint centering From 169896dc991a5d2956eb912d305254d3d450f52f Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Mon, 7 Jul 2025 23:38:49 +0200 Subject: [PATCH 24/28] fix failing test on windows --- tests/testthat/test-save.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-save.R b/tests/testthat/test-save.R index 97d0732..4d70552 100644 --- a/tests/testthat/test-save.R +++ b/tests/testthat/test-save.R @@ -36,5 +36,5 @@ test_that("saveAsWorkbook", { wb <- createWorkbook() saveAsWorksheet(boeker, wb) - expect_error(saveAsWorksheet(boeker, wb), "Worksheet 'grid' already exists") + expect_error(saveAsWorksheet(boeker, wb), "Worksheet ['\"]grid['\"] already exists") # windows renders \" }) From 0731f1e89e522b26d618d3e6e2db67b1ddf093b5 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Tue, 8 Jul 2025 10:43:56 +0200 Subject: [PATCH 25/28] `makeGrid` and `randomGrid` can add construct pole preference. --- NEWS.md | 1 + R/dev-functions.r | 20 ++++++++++---------- R/repgrid-basicops.r | 1 + man/randomGrid.Rd | 8 +++++--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/NEWS.md b/NEWS.md index d17583e..15050f7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # OpenRepGrid 0.1.18 +* `makeGrid` and `randomGrid` can add construct pole preference. * `saveAsExcel` can export a list of grids now (#67) * `saveAsWorksheet` to add grid as anew to an in `openxlsx` `Workbook` object. * `importExcel` now also understands the long format (#65) diff --git a/R/dev-functions.r b/R/dev-functions.r index 1252be5..2a3a0b7 100644 --- a/R/dev-functions.r +++ b/R/dev-functions.r @@ -22,37 +22,37 @@ #' @param options Use random sentences as constructs and elements (1) or #' not (0). If not, the elements and constructs are given #' default names and are numbered. +#' @param preferred Add preferred pole info? (default `TRUE`) #' @return `repgrid` object. #' #' @export #' @examples \dontrun{ -#' #' x <- randomGrid() #' x -#' x <- randomGrid(10, 25) +#' x <- randomGrid(10, 25, preferred = FALSE) #' x #' x <- randomGrid(10, 25, options = 0) #' x #' } #' -randomGrid <- function(nc = 10, ne = 15, nwc = 8, nwe = 5, range = c(1, 5), prob = NULL, options = 1) { +randomGrid <- function(nc = 10, ne = 15, nwc = 8, nwe = 5, range = c(1, 5), prob = NULL, options = 1, preferred = TRUE) { if (options == 1) { # full constructs and element names elem <- randomSentences(ne, nwe) left <- randomSentences(nc, nwc) right <- randomSentences(nc, nwc) } else { # short element and construct names - elem <- paste("element", seq_len(ne), sep = "") - left <- paste("lconstruct", seq_len(nc), sep = "") - right <- paste("rconstruct", seq_len(nc), sep = "") + elem <- paste("element", seq_len(ne)) + left <- paste("left pole", seq_len(nc)) + right <- paste("right pole", seq_len(nc)) } - scores <- sample(range[1]:range[2], nc * ne, - replace = TRUE, prob = prob - ) + scores <- sample(range[1]:range[2], nc * ne, replace = TRUE, prob = prob) + preferred_pole <- sample(c("left", "right", NA_character_), replace = TRUE, size = nc, prob = c(.7, .2, .1)) args <- list( name = elem, l.name = left, r.name = right, - scores = scores + scores = scores, + preferred_pole = if (preferred) preferred_pole else NULL ) x <- makeRepgrid(args) setScale(x, min = range[1], max = range[2]) diff --git a/R/repgrid-basicops.r b/R/repgrid-basicops.r index 47a6489..653a36c 100644 --- a/R/repgrid-basicops.r +++ b/R/repgrid-basicops.r @@ -1458,6 +1458,7 @@ makeRepgrid <- function(args) { x <- do.call(rg.setCoupled, l) # if no coupled argument then coupled=TRUE l <- c(list(x = x), args) # make a new repgrid object x <- do.call(setScale, l) # set scale if min and max arg is provided + preferredPoles(x) <- l$preferred_pole x } # args <- list( name=c("element_1", "element_2", "element_3", "element_4"), diff --git a/man/randomGrid.Rd b/man/randomGrid.Rd index 1549283..28ac47f 100644 --- a/man/randomGrid.Rd +++ b/man/randomGrid.Rd @@ -11,7 +11,8 @@ randomGrid( nwe = 5, range = c(1, 5), prob = NULL, - options = 1 + options = 1, + preferred = TRUE ) } \arguments{ @@ -31,6 +32,8 @@ If \code{NULL} (default) the distribution is uniform.} \item{options}{Use random sentences as constructs and elements (1) or not (0). If not, the elements and constructs are given default names and are numbered.} + +\item{preferred}{Add preferred pole info? (default \code{TRUE})} } \value{ \code{repgrid} object. @@ -41,10 +44,9 @@ exploring distributions of indexes etc. } \examples{ \dontrun{ - x <- randomGrid() x -x <- randomGrid(10, 25) +x <- randomGrid(10, 25, preferred = FALSE) x x <- randomGrid(10, 25, options = 0) x From f40083c9e5b48bbbc733d808044c2fd29c31e3fc Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Tue, 8 Jul 2025 15:10:15 +0200 Subject: [PATCH 26/28] refactor: saveAsEcxcel, saveAsWorksheet * also examples, tests, vignette --- DESCRIPTION | 2 +- NEWS.md | 6 ++--- R/export.r | 26 +++++++++++-------- R/import.r | 22 ++++++++-------- R/utils.r | 7 +++++ inst/examples/example-importExcel.R | 7 ++++- inst/examples/example-save-as-worksheet.R | 13 +++++++--- inst/extdata/grid_03.xlsx | Bin 0 -> 12367 bytes man/importExcel.Rd | 12 ++++++--- man/saveAsExcel.Rd | 11 +++++--- man/saveAsWorksheet.Rd | 22 +++++++++++----- tests/testthat/test-import-export.R | 17 ++++++++++++ tests/testthat/test-save.R | 11 +++++--- vignettes/web/loading.Rmd | 30 +++++++++++++++------- 14 files changed, 130 insertions(+), 56 deletions(-) create mode 100644 inst/extdata/grid_03.xlsx diff --git a/DESCRIPTION b/DESCRIPTION index 992bd58..61f1d07 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -17,7 +17,7 @@ Description: Analyze repertory grids, a qualitative-quantitative 2004, ISBN: 978-0-470-09080-0). The package is part of the The package is part of the project. Version: 0.1.18 -Date: 2025-07-07 +Date: 2025-07-08 Encoding: UTF-8 URL: https://github.com/markheckmann/OpenRepGrid Imports: diff --git a/NEWS.md b/NEWS.md index 15050f7..5a21f3e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,9 @@ # OpenRepGrid 0.1.18 -* `makeGrid` and `randomGrid` can add construct pole preference. * `saveAsExcel` can export a list of grids now (#67) -* `saveAsWorksheet` to add grid as anew to an in `openxlsx` `Workbook` object. -* `importExcel` now also understands the long format (#65) +* `saveAsWorksheet` adds a grid as a new sheet to a `openxlsx` `Workbook` object. +* `makeGrid` and `randomGrid` can add construct pole preference. +* `importExcel` now also understands the long format (#65) and can import from several sheets at once (#68) * `importDataframe` converts a dataframe into a repgrid. Three different formats can be read in. See the sample dataframes `df_element_columns`, `df_construct_columns`, and `df_long` (#61) * `saveAsExcel` now supports output in wide and long format. The output is also formatted now (#64) diff --git a/R/export.r b/R/export.r index 01c31c2..1f2956b 100644 --- a/R/export.r +++ b/R/export.r @@ -173,27 +173,29 @@ saveAsTxt <- function(x, file = NA) { #' Save grids as Microsoft Excel file (.xlsx) #' -#' `saveAsExcel` will save one or more grids as MS Excel file (`.xlsx`). +#' `saveAsExcel` will save one or more grids in an Excel file (`.xlsx`). #' #' @param x A `repgrid` object or a list of grids. #' @param file File path. Suffix must be `.xlsx`. #' @param format Two output formats are supported: `wide` (default) where each column represents one element, each row #' represent one constructs (a common grid representation), and `long` where each row contains an element-construct #' combination and the corresponding rating value. See [importExcel()] for details and examples. -#' @param sheet Sheet name (defaults to `grid`). If `x` is a list of grids, the name of the list entry is used. -#' If it has no name, a sequential index is appended to `sheet`. +#' @param sheet Vector of sheet names with same length as `x`. If `NULL` (default), `default_sheet` is used. If `x` +#' is a list if grids, a sequential index is appended. For named list entries (if `x` is a list of grids), the name +#' overwrites the default sheet name. +#' @param default_sheet Default sheet name to use if not supplied in `sheet` or via list names of `x`. #' @return Invisibly returns file path. #' @export #' @seealso [importExcel()], [saveAsWorksheet()] #' @example inst/examples/example-save-as-excel.R #' -saveAsExcel <- function(x, file, format = "wide", sheet = "grid") { +saveAsExcel <- function(x, file, format = "wide", sheet = NULL, default_sheet = "grid") { ext <- tools::file_ext(file) if (ext != "xlsx") { stop("The file extension must be '.xlsx'. Found '", ext, "' instead.", call. = FALSE) } wb <- openxlsx::createWorkbook() - wb <- saveAsWorksheet(x, wb = wb, format = format, sheet = sheet) + wb <- saveAsWorksheet(x, wb = wb, format = format, sheet = sheet, default_sheet = default_sheet) openxlsx::saveWorkbook(wb, file, overwrite = TRUE) invisible(file) } @@ -204,7 +206,6 @@ saveAsExcel <- function(x, file, format = "wide", sheet = "grid") { #' `saveAsWorksheet` will add one or more grids to an a [openxlsx](https://CRAN.R-project.org/package=openxlsx) #' `Workbook` object. #' -#' @param x A `repgrid` object or a list of grids. #' @param wb A [openxlsx](https://CRAN.R-project.org/package=openxlsx) `Workbook` object. #' @inheritParams saveAsExcel #' @return Invisibly returns Workbook object. @@ -212,16 +213,21 @@ saveAsExcel <- function(x, file, format = "wide", sheet = "grid") { #' @seealso [saveAsExcel()] #' @example inst/examples/example-save-as-worksheet.R #' -saveAsWorksheet <- function(x, wb, format = "wide", sheet = "grid") { +saveAsWorksheet <- function(x, wb, format = "wide", sheet = NULL, default_sheet = "grid") { stop_if_not_inherits(wb, "Workbook") - if (!is_list_of_repgrids(x)) { + sheet <- sheet %||% default_sheet wb <- add_one_sheet_with_grid(x, wb = wb, format = format, sheet = sheet) } else { ii <- seq_along(x) list_names <- get_names_na(x) - sheets_numbered <- paste(sheet %||% "grid", ii) - sheets <- ifelse(!is.na(list_names), list_names, sheets_numbered) + # sheet name precedence: sheet, list, default + if (length(sheet) == length(x)) { + sheets <- sheet + } else { # if (is.null(sheet) + default_names <- paste(default_sheet, ii) + sheets <- ifelse(is.na(list_names), default_names, list_names) + } for (i in ii) { wb <- add_one_sheet_with_grid(x[[i]], wb = wb, format = format, sheet = sheets[i]) } diff --git a/R/import.r b/R/import.r index ab8cef0..66ee604 100644 --- a/R/import.r +++ b/R/import.r @@ -1668,27 +1668,29 @@ importDataframe <- function(x, format = "element_columns", rmin = NULL, rmax = N #' pass `rmin` and `rmax` as arguments in the function call. #' #' @param file Path(s) to Excel file(s) (suffix `.xlsx`). -#' @param sheet Name or index of sheet with grid data. +#' @param sheet Names or indexes of sheet with grid data to import. #' @param format Two formats are supported. `wide` (default): each column represents one element, each row represent #' one constructs. `long`: each row contains one rating value for a element-construct combination. See #' sections below and examples. #' @param rmin,rmax Min and max of the rating scale (`numeric`, default `NULL`). -#' @return A single `repgrid` object (one inpput file) or a list of `repgrid` objects (several input files). +#' @return A `repgrid` object (one input file) or a named list with `repgrid` objects (several input files). List names are +#' filename + sheet. #' @export #' @family import #' @example inst/examples/example-importExcel.R #' importExcel <- function(file, sheet = 1, format = "wide", rmin = NULL, rmax = NULL) { format <- match.arg(tolower(format), c("wide", "long")) - - rgs <- if (format == "wide") { - lapply(file, import_excel_wide, sheet = sheet, rmin = rmin, rmax = rmax) - } else { - lapply(file, import_excel_long, sheet = sheet, rmin = rmin, rmax = rmax) - } - + import_fun <- ifelse(format == "wide", import_excel_wide, import_excel_long) + df_import <- expand.grid(file = file, sheet = sheet, stringsAsFactors = FALSE) # read all file-sheet combinations + rgs <- mapply(import_fun, + file = df_import$file, sheet = df_import$sheet, + MoreArgs = list(rmin = rmin, rmax = rmax) + ) + filenames <- file_path_sans_ext(basename(df_import$file)) + names(rgs) <- paste0(filenames, "-", df_import$sheet) if (length(rgs) == 1) { - return(rgs[[1]]) # no list, just a single repgrid object + return(rgs[[1]]) # no list, just single repgrid object } else { return(rgs) # list of repgrid objects } diff --git a/R/utils.r b/R/utils.r index 1b71c01..74db254 100644 --- a/R/utils.r +++ b/R/utils.r @@ -1042,3 +1042,10 @@ get_names_na <- function(x) { ifelse(nzchar(nm), nm, NA_character_) } } + +# from tools::file_path_sans_ext +file_path_sans_ext <- function (x, compression = FALSE) { + if (compression) + x <- sub("[.](gz|bz2|xz)$", "", x) + sub("([^.]+)\\.[[:alnum:]]+$", "\\1", x) +} diff --git a/inst/examples/example-importExcel.R b/inst/examples/example-importExcel.R index 96cb18c..5993f1d 100644 --- a/inst/examples/example-importExcel.R +++ b/inst/examples/example-importExcel.R @@ -2,10 +2,15 @@ file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") rg_1 <- importExcel(file, sheet = "wide") rg_2 <- importExcel(file, sheet = "long", format = "long") -# Open Sample file to inspect the two (requires Excel to be installed). +# Open sample file to inspect it (requires Excel to be installed). \dontrun{ browseURL(file) # may not work on all systems } # Import more than one Excel file files <- system.file("extdata", c("grid_01.xlsx", "grid_02.xlsx"), package = "OpenRepGrid") rgs <- importExcel(files) # returns a list of grids + +# Impoort from several sheets at once (all must have same format) +file <- system.file("extdata", "grid_03.xlsx", package = "OpenRepGrid") +rgs <- importExcel(file, sheet = 1:3) # by index +rgs <- importExcel(file, sheet = c("grid 1", "grid 2", "grid 3")) # or by name diff --git a/inst/examples/example-save-as-worksheet.R b/inst/examples/example-save-as-worksheet.R index 0b480b7..a5b3d00 100644 --- a/inst/examples/example-save-as-worksheet.R +++ b/inst/examples/example-save-as-worksheet.R @@ -5,13 +5,18 @@ wb <- createWorkbook() # add grid to worksheet saveAsWorksheet(boeker, wb, sheet = "boeker") -# add several grids (2nd has a name) -l <- list(boeker, "feixas' grid" = feixas2004) # -saveAsWorksheet(l, wb) # name sheet +# add several grids with explicit sheet names +l <- list(bell2010, feixas2004) +saveAsWorksheet(l, wb, sheet = c("Bell 2010", "Feixas 2004")) +# list names are used as sheet names. Without name, the default applies. +l <- list(boeker, "Fransella et al. 2003" = fbb2003) +saveAsWorksheet(l, wb) + + +# save as Excel file file <- tempfile(fileext = ".xlsx") saveWorkbook(wb, file) - \dontrun{ browseURL(file) # may not work on all systems } diff --git a/inst/extdata/grid_03.xlsx b/inst/extdata/grid_03.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ccca704a3b9c7995114b3ab5efb8944dff4ab90b GIT binary patch literal 12367 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 TmM}25(4X(n%NY@t`)~gXiHo4& literal 0 HcmV?d00001 diff --git a/man/importExcel.Rd b/man/importExcel.Rd index f5875a0..8ef15ee 100644 --- a/man/importExcel.Rd +++ b/man/importExcel.Rd @@ -9,7 +9,7 @@ importExcel(file, sheet = 1, format = "wide", rmin = NULL, rmax = NULL) \arguments{ \item{file}{Path(s) to Excel file(s) (suffix \code{.xlsx}).} -\item{sheet}{Name or index of sheet with grid data.} +\item{sheet}{Names or indexes of sheet with grid data to import.} \item{format}{Two formats are supported. \code{wide} (default): each column represents one element, each row represent one constructs. \code{long}: each row contains one rating value for a element-construct combination. See @@ -18,7 +18,8 @@ sections below and examples.} \item{rmin, rmax}{Min and max of the rating scale (\code{numeric}, default \code{NULL}).} } \value{ -A single \code{repgrid} object (one inpput file) or a list of \code{repgrid} objects (several input files). +A \code{repgrid} object (one input file) or a named list with \code{repgrid} objects (several input files). List names are +filename + sheet. } \description{ You can define a grid in a Microsoft Excel file (suffix \code{.xlsx}). The file must have one of @@ -67,13 +68,18 @@ file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") rg_1 <- importExcel(file, sheet = "wide") rg_2 <- importExcel(file, sheet = "long", format = "long") -# Open Sample file to inspect the two (requires Excel to be installed). +# Open sample file to inspect it (requires Excel to be installed). \dontrun{ browseURL(file) # may not work on all systems } # Import more than one Excel file files <- system.file("extdata", c("grid_01.xlsx", "grid_02.xlsx"), package = "OpenRepGrid") rgs <- importExcel(files) # returns a list of grids + +# Impoort from several sheets at once (all must have same format) +file <- system.file("extdata", "grid_03.xlsx", package = "OpenRepGrid") +rgs <- importExcel(file, sheet = 1:3) # by index +rgs <- importExcel(file, sheet = c("grid 1", "grid 2", "grid 3")) # or by name } \seealso{ Import data diff --git a/man/saveAsExcel.Rd b/man/saveAsExcel.Rd index 6e8823e..e3dff7a 100644 --- a/man/saveAsExcel.Rd +++ b/man/saveAsExcel.Rd @@ -4,7 +4,7 @@ \alias{saveAsExcel} \title{Save grids as Microsoft Excel file (.xlsx)} \usage{ -saveAsExcel(x, file, format = "wide", sheet = "grid") +saveAsExcel(x, file, format = "wide", sheet = NULL, default_sheet = "grid") } \arguments{ \item{x}{A \code{repgrid} object or a list of grids.} @@ -15,14 +15,17 @@ saveAsExcel(x, file, format = "wide", sheet = "grid") represent one constructs (a common grid representation), and \code{long} where each row contains an element-construct combination and the corresponding rating value. See \code{\link[=importExcel]{importExcel()}} for details and examples.} -\item{sheet}{Sheet name (defaults to \code{grid}). If \code{x} is a list of grids, the name of the list entry is used. -If it has no name, a sequential index is appended to \code{sheet}.} +\item{sheet}{Vector of sheet names with same length as \code{x}. If \code{NULL} (default), \code{default_sheet} is used. If \code{x} +is a list if grids, a sequential index is appended. For named list entries (if \code{x} is a list of grids), the name +overwrites the default sheet name.} + +\item{default_sheet}{Default sheet name to use if not supplied in \code{sheet} or via list names of \code{x}.} } \value{ Invisibly returns file path. } \description{ -\code{saveAsExcel} will save one or more grids as MS Excel file (\code{.xlsx}). +\code{saveAsExcel} will save one or more grids in an Excel file (\code{.xlsx}). } \examples{ # save one grid in wide format (default) diff --git a/man/saveAsWorksheet.Rd b/man/saveAsWorksheet.Rd index 1c39b57..1d938f4 100644 --- a/man/saveAsWorksheet.Rd +++ b/man/saveAsWorksheet.Rd @@ -4,7 +4,7 @@ \alias{saveAsWorksheet} \title{Add grids as sheets to an openxlsx Workbook} \usage{ -saveAsWorksheet(x, wb, format = "wide", sheet = "grid") +saveAsWorksheet(x, wb, format = "wide", sheet = NULL, default_sheet = "grid") } \arguments{ \item{x}{A \code{repgrid} object or a list of grids.} @@ -15,8 +15,11 @@ saveAsWorksheet(x, wb, format = "wide", sheet = "grid") represent one constructs (a common grid representation), and \code{long} where each row contains an element-construct combination and the corresponding rating value. See \code{\link[=importExcel]{importExcel()}} for details and examples.} -\item{sheet}{Sheet name (defaults to \code{grid}). If \code{x} is a list of grids, the name of the list entry is used. -If it has no name, a sequential index is appended to \code{sheet}.} +\item{sheet}{Vector of sheet names with same length as \code{x}. If \code{NULL} (default), \code{default_sheet} is used. If \code{x} +is a list if grids, a sequential index is appended. For named list entries (if \code{x} is a list of grids), the name +overwrites the default sheet name.} + +\item{default_sheet}{Default sheet name to use if not supplied in \code{sheet} or via list names of \code{x}.} } \value{ Invisibly returns Workbook object. @@ -33,13 +36,18 @@ wb <- createWorkbook() # add grid to worksheet saveAsWorksheet(boeker, wb, sheet = "boeker") -# add several grids (2nd has a name) -l <- list(boeker, "feixas' grid" = feixas2004) # -saveAsWorksheet(l, wb) # name sheet +# add several grids with explicit sheet names +l <- list(bell2010, feixas2004) +saveAsWorksheet(l, wb, sheet = c("Bell 2010", "Feixas 2004")) + +# list names are used as sheet names. Without name, the default applies. +l <- list(boeker, "Fransella et al. 2003" = fbb2003) +saveAsWorksheet(l, wb) + +# save as Excel file file <- tempfile(fileext = ".xlsx") saveWorkbook(wb, file) - \dontrun{ browseURL(file) # may not work on all systems } diff --git a/tests/testthat/test-import-export.R b/tests/testthat/test-import-export.R index 8855e95..90f0da5 100644 --- a/tests/testthat/test-import-export.R +++ b/tests/testthat/test-import-export.R @@ -34,6 +34,7 @@ test_that("importTxt - RATINGS", { test_that("export-import - roundtrip", { g_orig <- boeker + # one grid file_wide <- saveAsExcel(g_orig, file = tempfile(fileext = ".xlsx"), format = "wide") g_wide <- importExcel(file_wide, format = "wide") expect_identical(g_orig, g_wide) @@ -41,6 +42,22 @@ test_that("export-import - roundtrip", { file_long <- saveAsExcel(g_orig, file = tempfile(fileext = ".xlsx"), format = "long") g_long <- importExcel(file_long, format = "long") expect_identical(g_orig, g_long) + + # several grids / sheets + g_orig <- randomGrids(options = 0) + file_several <- saveAsExcel(g_orig, tempfile(fileext = ".xlsx")) + + sheets <- seq_along(g_orig) + g_many <- importExcel(file_several, sheet = sheets) + filename <- file_path_sans_ext(basename(file_several)) + expect_equal(names(g_many), paste0(filename, "-", sheets)) # names contain file + sheet index + expect_equal(g_orig, unname(g_many)) # somewhat unclear why not identical + + sheets <- paste("grid", seq_along(g_orig)) + g_many <- importExcel(file_several, sheet = sheets) + filename <- file_path_sans_ext(basename(file_several)) + expect_equal(names(g_many), paste0(filename, "-", sheets)) # names contain file + sheet name + expect_equal(g_orig, unname(g_many)) # somewhat unclear why not identical }) diff --git a/tests/testthat/test-save.R b/tests/testthat/test-save.R index 4d70552..195eacf 100644 --- a/tests/testthat/test-save.R +++ b/tests/testthat/test-save.R @@ -6,15 +6,18 @@ test_that("saveAsExcel", { expect_equal(getSheetNames(file), "grid") rgs <- randomGrids(nc = 3) - file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx")) + file <- tempfile(fileext = ".xlsx") + saveAsExcel(rgs, file) expect_equal(getSheetNames(file), paste("grid", 1:3)) rgs <- randomGrids(nc = 3) - file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx"), sheet = "xxxx") + file <- tempfile(fileext = ".xlsx") + saveAsExcel(rgs, file, default_sheet = "xxxx") expect_equal(getSheetNames(file), paste("xxxx", 1:3)) names(rgs) <- c("my grid", NA, NA) - file <- saveAsExcel(rgs, tempfile(fileext = ".xlsx")) + file <- tempfile(fileext = ".xlsx") + saveAsExcel(rgs, file) expect_equal(getSheetNames(file), c("my grid", "grid 2", "grid 3")) }) @@ -31,7 +34,7 @@ test_that("saveAsWorkbook", { wb <- createWorkbook() names(rgs) <- c("my grid", NA, NA) - saveAsWorksheet(rgs, wb, sheet = "xxxx") + saveAsWorksheet(rgs, wb, default_sheet = "xxxx") expect_equal(names(wb), c("my grid", "xxxx 2", "xxxx 3")) wb <- createWorkbook() diff --git a/vignettes/web/loading.Rmd b/vignettes/web/loading.Rmd index be6698b..9131b13 100644 --- a/vignettes/web/loading.Rmd +++ b/vignettes/web/loading.Rmd @@ -24,29 +24,34 @@ The `OpenRepGrid` R package is able to read files from different other grid prog #### Microsoft Excel files -You can define a grid file using Microsoft Excel. The `.xlsx` file has to be in a fixed format. See an example of a correct file below. The first row contains the minimum of the rating scale (red), the names of the elements (green) and the maximum of the rating scale (red). Below, every row contains the left construct pole (blue), the ratings (black) and the right construct pole (blue). The rightmost columns (purple) is optional and contains the preferred pole. Allowed values are +You can define a grid file using Excel. The `.xlsx` file has to be in a fixed format. See an example of a correct file below. The first row contains the minimum of the rating scale (red), the names of the elements (green) and the maximum of the rating scale (red). Below, every row contains the left construct pole (blue), the ratings (black) and the right construct pole (blue). The rightmost columns (purple) is optional and contains the preferred pole. Allowed values are `left`, `right`, `none` or an empty cell. reference diagram -To load an `.xlsx` file and save it into the object `x` type the following code to the R console (assuming your file is -named `sample.xlsx`). +The `OpenRepGrid` package comes with several sample Excel files. If you have Excel installed, you can try opening the sample file `grid_01.xlsx` as follows. ```{r eval=FALSE} -x <- importExcel("sample.xlsx") +file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") # path to sample file +browseURL(file) # may not work on all systems ``` -The `OpenRepGrid` package comes with an example Excel file. If you have Excel installed, you should be able to open it -by typing +You can import the sample file as follows: ```{r eval=FALSE} -file <- system.file("extdata", "grid_01.xlsx", package = "OpenRepGrid") -browseURL(file) # may not work on all systems +x <- importExcel(file) +``` + +If ax Excel file contains mutliple sheet with grid data (`grid_03.xlsx` has three sheets), you can import them like so. + +```{r eval=FALSE} +file <- system.file("extdata", "grid_03.xlsx", package = "OpenRepGrid") # path to sample file +x <- importExcel(file, sheet = 1:3) # indexes or sheet names to import ``` #### .txt files -If you do not have a grid program at hand you can define a grid using a standard text editor and by saving it as a +If you do not have Excel installed, you can define a grid using a text editor and by saving it as a `.txt` file. The `.txt` file has to be in a fixed format. There are three mandatory blocks each starting and ending with a predefined tag in uppercase letters. The first block starts with `ELEMENTS` and ends with` ⁠END ELEMENTS`⁠. It contains one element per line. The other mandatory blocks are `CONSTRUCTS` and `RATINGS` (see below). In the block @@ -167,6 +172,13 @@ The most convenient format is probably an Excel file. You can save one or more g saveAsExcel(boeker, file = "boeker.xlsx") # save it to the file "boeker.xlsx" ``` +You can save a list of grids to several sheets as follows. + +```{r eval=FALSE} +l <- list(boeker, bell2010) +saveAsExcel(l, file = "grids.xlsx") # save it to the file "boeker.xlsx" +``` + #### .txt file To save a grid as a `.txt` file use the function `saveAsTxt`. It will save the grid as a .txt file in format used by `OpenRepGrid`. This file format can also easily be edited by hand (see `importTxt` for a description). From f69f6db1043982ef659d5ed913c880c032222b67 Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Tue, 8 Jul 2025 15:17:52 +0200 Subject: [PATCH 27/28] run styler & pkgdown --- R/utils.r | 5 +++-- README.Rmd | 4 ++-- README.md | 4 ++-- vignettes/web/loading.Rmd | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/R/utils.r b/R/utils.r index 74db254..5317e1f 100644 --- a/R/utils.r +++ b/R/utils.r @@ -1044,8 +1044,9 @@ get_names_na <- function(x) { } # from tools::file_path_sans_ext -file_path_sans_ext <- function (x, compression = FALSE) { - if (compression) +file_path_sans_ext <- function(x, compression = FALSE) { + if (compression) { x <- sub("[.](gz|bz2|xz)$", "", x) + } sub("([^.]+)\\.[[:alnum:]]+$", "\\1", x) } diff --git a/README.Rmd b/README.Rmd index b9a2b9e..8ed477c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -49,10 +49,10 @@ Install the latest release version from [CRAN](https://cran.r-project.org/web/pa install.packages("OpenRepGrid", dep = TRUE) -Install a development version from github by referencing a the dev branch (e.g., `0.1.18`): +Install a development version from github by referencing a the dev branch (e.g., `0.1.19`): library(devtools) - install_github("markheckmann/OpenRepGrid@01.1.18") + install_github("markheckmann/OpenRepGrid@01.1.19") To load the OpenRepGrid package after installation type diff --git a/README.md b/README.md index 5fb8fee..1f0f54a 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,10 @@ Install the latest release version from install.packages("OpenRepGrid", dep = TRUE) Install a development version from github by referencing a the dev -branch (e.g., `0.1.18`): +branch (e.g., `0.1.19`): library(devtools) - install_github("markheckmann/OpenRepGrid@01.1.18") + install_github("markheckmann/OpenRepGrid@01.1.19") To load the OpenRepGrid package after installation type diff --git a/vignettes/web/loading.Rmd b/vignettes/web/loading.Rmd index 9131b13..60e06ea 100644 --- a/vignettes/web/loading.Rmd +++ b/vignettes/web/loading.Rmd @@ -156,7 +156,7 @@ x <- importGridsuite("gridsuite.xml") # file in current R working directory #### sci:vesco ```{r eval=FALSE} -x <- importScivesco("scivesco.scires") # file in current R working directory +x <- importScivesco("scivesco.scires") # file in current R working directory ``` From fad34683712965c0c3c363d23f75b7fa4260014d Mon Sep 17 00:00:00 2001 From: Mark Heckmann Date: Tue, 8 Jul 2025 16:27:06 +0200 Subject: [PATCH 28/28] CRAN comments for release --- CRAN-SUBMISSION | 3 --- cran-comments.md | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 CRAN-SUBMISSION diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION deleted file mode 100644 index acf7ac3..0000000 --- a/CRAN-SUBMISSION +++ /dev/null @@ -1,3 +0,0 @@ -Version: 0.1.17 -Date: 2025-03-02 08:04:21 UTC -SHA: a3c09fdbce18b9424775820d9d01304294ea806f diff --git a/cran-comments.md b/cran-comments.md index 8550a50..cd608ad 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,8 +1,8 @@ ## Test environments -* MacOS 14.7.2, R 4.4.3 -* Microsoft Windows Server 2022, R 4.4.3 -* Ubuntu 22.04.2 LTS, R 4.4.3 +* MacOS 14.7.6, R 4.5.1 +* Microsoft Windows Server 2022, R 4.5.1 +* Ubuntu 24.04.2 LTS, R 4.5.1 ## R CMD check results