Skip to content

Commit 141d2ff

Browse files
authored
Tidy up checks into utils, squash bugs (#29)
* Tidy up checks into utils, close #24, close #25 * Update DESCRIPTION, NEWS, given 0.2.1
1 parent 0a68387 commit 141d2ff

File tree

11 files changed

+182
-101
lines changed

11 files changed

+182
-101
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: pixeltrix
22
Title: Simple Interactive Pixel Art
3-
Version: 0.2.0
3+
Version: 0.2.1
44
Authors@R:
55
person("Matt", "Dray", , "[email protected]", role = c("aut", "cre"))
66
Description: A very simple 'pixel art' tool that lets you click squares

NEWS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# pixeltrix 0.2.1
2+
3+
* Added additional input checks to check-utils.R.
4+
* `draw_pixels()` now finds `n_states` (#24).
5+
* Allow for an increased number of states in `edit_pixels()` (#25).
6+
17
# pixeltrix 0.2.0
28

39
* A named character of colours is now provided as an extra attribute to matrices output from `click_pixels()` (#3, #17, thanks @TimTaylor).
@@ -6,7 +12,6 @@
612
* Updated and expanded function documentation and README (#21).
713
* Reused input checks have been generalised into 'R/utils-check.R'.
814
* Expanded tests to cover argument input errors.
9-
*
1015

1116
# pixeltrix 0.1.3
1217

R/animate.R

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ frame_pixels <- function(
5050
grid = TRUE
5151
) {
5252

53-
.check_n_numeric(n_rows, n_cols, n_states)
53+
.check_n_arg_numeric(n_rows)
54+
.check_n_arg_numeric(n_cols)
55+
.check_n_arg_numeric(n_states)
5456
.check_colours_char(colours)
55-
.check_colours_len(colours, n_states)
57+
.check_colours_len(n_states, colours)
5658
.check_grid(grid)
5759

5860
m_list <- list()
@@ -129,26 +131,14 @@ gif_pixels <- function(
129131
...
130132
) {
131133

132-
if (
133-
!is.list(frames) |
134-
!all(sapply(frames, function(x) identical(dim(x), dim(frames[[1]]))))
135-
) {
136-
stop(
137-
"Argument 'frames' must be a list of matrices of the same dimensions ",
138-
"(preferably produced by the frame_pixels() function).",
139-
call. = FALSE
140-
)
141-
}
134+
.check_frames_dims(frames)
135+
.check_file_gif(file)
142136

143-
if (
144-
!inherits(file, "character") |
145-
length(file) != 1 |
146-
tools::file_ext(file) != "gif"
147-
) {
148-
stop(
149-
"Argument 'file' must be a character-string filepath ending '.gif'.",
150-
call. = FALSE
151-
)
137+
# Retrieve n_states from attributes or matrix values
138+
if (!is.null(attr(frames[[1]], "colours"))) {
139+
n_states <- length(attr(frames[[1]], "colours"))
140+
} else if (is.null(attr(frames, "colours"))) {
141+
n_states <- max(unique(unlist(frames))) + 1L
152142
}
153143

154144
# If the first frame has a 'colours' attribute, then use these
@@ -163,7 +153,7 @@ gif_pixels <- function(
163153
}
164154

165155
.check_colours_char(colours)
166-
.check_colours_unique(frames, colours)
156+
.check_colours_states(frames, n_states, colours)
167157

168158
# Write to
169159
gifski::save_gif(

R/click.R

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -48,27 +48,33 @@ click_pixels <- function(
4848
grid = TRUE
4949
) {
5050

51-
.check_n_numeric(n_rows, n_cols, n_states)
51+
# Check inputs
52+
.check_n_arg_numeric(n_rows)
53+
.check_n_arg_numeric(n_cols)
54+
.check_n_arg_numeric(n_states)
5255
.check_colours_char(colours)
53-
.check_colours_len(colours, n_states)
56+
.check_colours_len(n_states, colours)
5457
.check_grid(grid)
5558

59+
# Convert to integer if required
5660
n_rows <- .convert_to_int(n_rows)
5761
n_cols <- .convert_to_int(n_cols)
5862
n_states <- .convert_to_int(n_states)
5963

64+
# Generate a palette of gradated greys if colours not provided by user
6065
if (is.null(colours)) {
6166
get_greys <- grDevices::colorRampPalette(c("white", "grey20"))
62-
colours <- get_greys(n_states) # gradated colours from white to dark grey
67+
colours <- get_greys(n_states)
6368
}
6469

70+
# Initiate matrix, draw, let user interact
6571
m <- matrix(0L, n_rows, n_cols)
66-
6772
.plot_canvas(m, n_states, colours)
6873
if (grid) .add_grid(m)
6974
m <- .repeat_loop(m, n_states, colours, grid)
7075

71-
attr(m, "colours") <- stats::setNames(colours, seq(0, n_states - 1))
76+
# Add colours as an attribute to returned matrix
77+
attr(m, "colours") <- stats::setNames(colours, seq(0, n_states - 1))
7278

7379
m
7480

@@ -134,58 +140,38 @@ edit_pixels <- function(
134140
grid = TRUE
135141
) {
136142

143+
# Check inputs
137144
.check_matrix(m)
138145
.check_grid(grid)
146+
.check_n_arg_numeric(n_states, null_allowed = TRUE)
147+
.check_n_states_size(m, n_states)
139148

140-
if (!is.null(n_states)) {
141-
if (!is.numeric(n_states)) {
142-
stop(
143-
"Argument 'n_states' must be a numeric value or NULL.",
144-
call. = FALSE
145-
)
146-
}
147-
}
148-
149-
if (!is.null(n_states) && n_states < max(m + 1L)) {
150-
stop(
151-
"The number of states, 'n_states', can't be less than ",
152-
"the maximum value in the provided matrix, 'm'.",
153-
call. = FALSE
154-
)
155-
}
156-
157-
# Coerce n_states to integer, if provided
158-
if (!is.null(n_states)) {
149+
# Handle n_states
150+
if (!is.null(n_states)) { # if provided, convert to integer
159151
n_states <- as.integer(n_states)
152+
} else if (is.null(n_states) & !is.null(attr(m, "colours"))) { # via attribute
153+
n_states <- length(attr(m, "colours"))
154+
} else if (is.null(n_states) & is.null(attr(m, "colours"))) { # via matrix
155+
n_states <- max(unique(as.vector(m)) + 1L)
160156
}
161157

162-
# Otherwise get n_state from attributes
163-
if (is.null(n_states) & !is.null(attr(m, "colours"))) {
164-
n_states <- length(attr(m, "colours")) # n colours, so n states
165-
}
166-
167-
# Otherwise take n_states from content of input matrix
168-
if (is.null(n_states) & is.null(attr(m, "colours"))) {
169-
n_states <- length(unique(as.vector(m)))
170-
}
171-
172-
# Take colours from attributes of input matrix, if present
173-
if (is.null(colours) & !is.null(attr(m, "colours"))) {
158+
# Handle colours if not provided
159+
if (is.null(colours) & !is.null(attr(m, "colours"))) { # via attribute
174160
colours <- attr(m, "colours")
175-
}
176-
177-
# If no 'colours' attribute and colours is NULL, then choose gradated greys
178-
if (is.null(colours)) {
161+
} else if (is.null(colours)) { # otherwise a grey palette
179162
get_greys <- grDevices::colorRampPalette(c("white", "grey20"))
180-
colours <- get_greys(n_states) # gradated colours from white to dark grey
163+
colours <- get_greys(n_states)
181164
}
182165

183-
# .check_colours_unique(m, colours)
166+
# Check n_states and colours values match
167+
.check_colours_states(m, n_states, colours)
184168

169+
# Draw matrix, let user interact
185170
.plot_canvas(m, n_states, colours)
186171
if (grid) .add_grid(m)
187172
m <- .repeat_loop(m, n_states, colours, grid)
188173

174+
# Add colours as an attribute to returned matrix
189175
attr(m, "colours") <- stats::setNames(colours, seq(0, n_states - 1))
190176

191177
m

R/draw.R

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,28 @@ draw_pixels <- function(m, colours = NULL) {
2525

2626
.check_matrix(m)
2727

28+
# Retrieve n_states from attributes or matrix values
29+
if (!is.null(attr(m, "colours"))) {
30+
n_states <- length(attr(m, "colours"))
31+
} else if (is.null(attr(m, "colours"))) {
32+
n_states <- max(unique(as.vector(m))) + 1L
33+
}
34+
2835
# Take colours from attributes of input matrix, if present
2936
if (is.null(colours) & !is.null(attr(m, "colours"))) {
3037
colours <- attr(m, "colours")
3138
}
3239

33-
# If matrix has no 'colour' attribute, create gradated grey palette
34-
if (is.null(colours)) {
40+
# If matrix has no 'colours' attribute, create gradated grey palette
41+
if (is.null(colours) & is.null(attr(m, "colours"))) {
3542
get_greys <- grDevices::colorRampPalette(c("white", "grey20"))
3643
colours <- get_greys(n_states) # gradated colours from white to dark grey
3744
}
3845

39-
.check_colours_unique(m, colours)
46+
# Check number of colours provided
47+
.check_colours_states(m, n_states, colours)
4048

41-
par_start <- graphics::par(mar = rep(0, 4))
49+
par_start <- graphics::par(mar = rep(0, 4)) # set margins, store previous par
4250

4351
graphics::image(
4452
t(m[nrow(m):1, ]), # reverse matrix rows and transpose

R/utils-check.R

Lines changed: 101 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,41 @@
99

1010
}
1111

12-
.check_n_numeric <- function(n_rows, n_cols, n_states) {
12+
.check_n_arg_numeric <- function(n_arg, null_allowed = FALSE) {
1313

14-
if (
15-
is.logical(n_rows) | is.logical(n_states) | is.logical(n_cols) |
16-
!is.numeric(c(n_rows, n_cols, n_states))
17-
) {
14+
if (!null_allowed) { # used in click_pixels, where defaults are provided
15+
16+
if (is.logical(n_arg) | !is.numeric(c(n_arg))) {
17+
stop(
18+
"Argument '", deparse(substitute(n_arg)), "' must be numeric.",
19+
call. = FALSE
20+
)
21+
}
22+
23+
}
24+
25+
if (null_allowed) { # used in edit_pixels, where default n_states is NULL
26+
27+
if (!is.null(n_arg) && !is.numeric(n_arg)) {
28+
stop(
29+
"Argument '", deparse(substitute(n_arg)), "' must be numeric or NULL.",
30+
call. = FALSE
31+
)
32+
}
33+
34+
}
35+
36+
37+
}
38+
39+
.check_n_states_size <- function(m, n_states) {
40+
41+
m_max <- max(m + 1L)
42+
43+
if (!is.null(n_states) && n_states < m_max) {
1844
stop(
19-
"Arguments 'n_rows', 'n_cols' and 'n_states' must be numeric values.",
45+
"Argument 'n_states' (", n_states, " detected) must be equal or greater ",
46+
"than the maximum value in the matrix 'm' (", m_max, " detected).",
2047
call. = FALSE
2148
)
2249
}
@@ -36,33 +63,58 @@
3663

3764
}
3865

39-
.check_colours_len <- function(colours, n_states) {
66+
.check_colours_len <- function(n_states, colours) {
4067

4168
if (!is.null(colours) && (length(colours) != n_states)) {
4269
stop(
43-
"Argument 'colours' must be a character vector of length 'n_states'.",
70+
"Argument 'colours' (", length(colours), " values provided) must be a ",
71+
"character vector of length 'n_states' (", n_states, ").",
4472
call. = FALSE
4573
)
4674
}
4775

4876
}
4977

50-
.check_colours_unique <- function(object, colours) {
78+
.check_colours_states <- function(object, n_states, colours) {
5179

52-
if (is.list(object)) {
53-
object <- unlist(object)
54-
}
80+
if (is.null(n_states)) {
81+
82+
if (is.matrix(object)) { # edit_pixels() is a matrix
83+
84+
colours_attr <- attr(object, "colours")
85+
86+
if (!is.null(colours_attr)) {
87+
n_states <- length(colours_attr)
88+
}
89+
90+
if (is.null(colours_attr)) {
91+
object <- as.vector(object)
92+
n_states <- max(unique(object)) + 1L
93+
}
5594

56-
if (is.matrix(object)) (
57-
object <- as.vector(object)
58-
)
95+
}
96+
97+
if (is.list(object)) { # frame_pixels() input is a list
98+
99+
colours_attr <- attr(object[[1]], "colours")
100+
101+
if (!is.null(colours_attr)) {
102+
n_states <- length(colours_attr)
103+
}
104+
105+
if (is.null(colours_attr)) {
106+
object <- unlist(object)
107+
n_states <- max(unique(object)) + 1L
108+
}
109+
110+
}
59111

60-
states_len <- length(unique(object))
112+
}
61113

62-
if (length(colours) != states_len) {
114+
if (length(colours) != n_states) {
63115
stop(
64-
"Length of argument 'colours' should match the number of unique ",
65-
"pixel states (", states_len, ").",
116+
"Number of colours (", length(colours), " detected) should match ",
117+
"the number of pixel states (", n_states, " detected).",
66118
call. = FALSE
67119
)
68120
}
@@ -79,3 +131,33 @@
79131
}
80132

81133
}
134+
135+
.check_frames_dims <- function(frames) {
136+
137+
if (
138+
!is.list(frames) |
139+
!all(sapply(frames, function(frame) identical(dim(frame), dim(frames[[1]]))))
140+
) {
141+
stop(
142+
"Argument 'frames' must be a list of matrices of the same dimensions ",
143+
"(preferably produced by the frame_pixels() function).",
144+
call. = FALSE
145+
)
146+
}
147+
148+
}
149+
150+
.check_file_gif <- function(file) {
151+
152+
if (
153+
!inherits(file, "character") |
154+
length(file) != 1 |
155+
tools::file_ext(file) != "gif"
156+
) {
157+
stop(
158+
"Argument 'file' must be a character-string filepath ending '.gif'.",
159+
call. = FALSE
160+
)
161+
}
162+
163+
}

0 commit comments

Comments
 (0)