1212# ' 800 x 800px; use Inf to plot the lowest resolution available.
1313# ' @param ch image channel(s) to be used for plotting (defaults to
1414# ' the first channel(s) available); use \code{channels()} to see
15- # ' which channels are available for a given \code{ImageArray}
16- # ' @param c character vector; colors to use for each channel.
17- # ' @param cl list of length-2 numeric vectors (non-negative, increasing);
18- # ' specifies channel-wise contrast limits - defaults to [0, 1] for all
19- # ' (ignored when \code{image(x, i)} is an RGB image;
20- # ' for convenience, any NULL = [0, 1], and n = [0, n]).
15+ # ' which channels are available for a given \code{ImageArray}
16+ # '
17+ # ' @param c plotting aesthetics; color
2118# '
2219# ' @return ggplot
2320# '
3128# ' plotImage(x, i=2, k=.))
3229# ' patchwork::wrap_plots(ms)
3330# '
34- # ' # custom colors
35- # ' cmy <- c("cyan", "magenta", "yellow")
36- # ' plotSpatialData() + plotImage(x, c=cmy)
37- # '
38- # ' # contrast limits
39- # ' plotSpatialData() + plotImage(x, c=cmy,
40- # ' cl=list(c(0.2,1), c(0,0.8), c(0,1)))
41- # '
4231# ' @import SpatialData
4332NULL
4433
4736# ' @export
4837plotSpatialData <- \() ggplot() + scale_y_reverse() + .theme
4938
50- .check_cl <- \(cl , d ) {
51- if (is.null(cl )) {
52- # default to [0, 1] for all channels
53- cl <- replicate(d , c(0 , 1 ), FALSE )
54- } else {
55- # should be a list with as many elements as channels
56- if (! is.list(cl )) stop(" 'cl' should be a list" )
57- if (length(cl ) != d ) stop(" 'cl' should be of length " , d )
58- for (. in seq_len(d )) {
59- # replace NULL by [0, 1] & n by [0, n]
60- if (is.null(cl [[. ]])) cl [[. ]] <- c(0 , 1 )
61- if (length(cl [[. ]]) == 1 ) {
62- if (cl [[. ]] < 0 ) stop(" scalar 'cl' can't be < 0" )
63- cl [[. ]] <- c(0 , cl [[. ]])
64- }
65- }
66- # elements should be length-2, numeric, non-negative, increasing
67- .f <- \(. ) length(. ) == 2 && is.numeric(. ) && all(. > = 0 ) && . [2 ] > . [1 ]
68- if (! all(vapply(cl , .f , logical (1 ))))
69- stop(" elements of 'cl' should be length-2," ,
70- " non-negative, increasing numeric vectors" )
71- }
72- return (cl )
73- }
74-
7539# merge/manage image channels
7640# if no colors and channels defined, return the first channel
7741# ' @importFrom grDevices col2rgb
7842# ' @noRd
79- .chs2rgb <- \(a , ch , c = NULL , cl = NULL ) {
80- cl <- .check_cl(cl , d <- dim(a )[1 ])
43+ .manage_channels <- \(a , ch , c = NULL ){
8144 if (length(ch ) > (n <- length(.DEFAULT_COLORS )) && is.null(c ))
8245 stop(" Only " , n , " default colors available, but" ,
8346 length(ch ), " are needed; please specify 'c'" )
8447 if (! is.null(c ) || (is.null(c ) && length(ch ) > 1 )) {
8548 if (is.null(c )) c <- .DEFAULT_COLORS [seq_along(ch )]
8649 c <- col2rgb(c )/ 255
8750 b <- array (0 , dim = c(3 , dim(a )[- 1 ]))
88- for (i in seq_len(d )) {
89- for (j in seq_len(3 )) {
90- rgb <- a [i ,,,drop = FALSE ]* c [j ,i ]
91- # apply upper contrast lim.
92- rgb <- rgb * (1 / cl [[i ]][2 ])
93- b [j ,,] <- b [j ,,,drop = FALSE ] + rgb
94- # apply lower contrast lim.
95- b [j ,,][b [j ,,] < cl [[i ]][1 ]] <- 0
96- }
51+ for (i in seq_len(dim(a )[1 ])) {
52+ b [1 ,,] <- b [1 ,,,drop = FALSE ] + a [i ,,,drop = FALSE ]* c [1 ,i ]
53+ b [2 ,,] <- b [2 ,,,drop = FALSE ] + a [i ,,,drop = FALSE ]* c [2 ,i ]
54+ b [3 ,,] <- b [3 ,,,drop = FALSE ] + a [i ,,,drop = FALSE ]* c [3 ,i ]
9755 }
9856 a <- pmin(b , 1 )
9957 } else {
@@ -106,22 +64,21 @@ plotSpatialData <- \() ggplot() + scale_y_reverse() + .theme
10664# ' @importFrom SpatialData getZarrArrayPath
10765# ' @importFrom Rarr zarr_overview
10866# ' @noRd
109- .get_img_dt <- \(a ) {
67+ .get_image_dtype <- \(a ) {
11068 pa <- getZarrArrayPath(a )
11169 df <- zarr_overview(pa , as_data_frame = TRUE )
11270 if (! is.null(dt <- df $ data_type )) return (dt )
11371}
11472
11573# normalize the image data given its data type
11674# ' @noRd
117- .norm_ia <- \(a , dt ) {
118- d <- dim(a )[1 ]
119- if (dt %in% names(.DTYPE_MAX_VALUES )) {
120- a <- a / .DTYPE_MAX_VALUES [dt ]
121- } else if (max(a ) > 1 ) {
122- for (i in seq_len(d ))
123- a [i ,,] <- a [i ,,] / max(a [i ,,])
124- }
75+ .normalize_image_array <- \(a , dt ){
76+ if (dt %in% names(.DTYPE_MAX_VALUES )) {
77+ a <- a / .DTYPE_MAX_VALUES [dt ]
78+ } else if (max(a ) > 1 ) {
79+ for (i in seq_len(dim(a )[1 ]))
80+ a [i ,,] <- a [i ,,]/ max(a [i ,,])
81+ }
12582 return (a )
12683}
12784
@@ -167,26 +124,24 @@ plotSpatialData <- \() ggplot() + scale_y_reverse() + .theme
167124 which.min(d )
168125}
169126
170- .get_img_data <- \(x , k = NULL , w = 800 , h = 800 ) {
127+ .get_plot_data <- \(x , k = NULL , w = 800 , h = 800 ) {
171128 if (! is.null(k )) return (data(x , k ))
172129 data(x , .guess_scale(x , w , h ))
173130}
174131
175132# ' @importFrom methods as
176133# ' @importFrom grDevices rgb
177134# ' @importFrom DelayedArray realize
178- .df_i <- \(x , k = NULL , ch = NULL , c = NULL , cl = NULL ) {
179- a <- .get_img_data(x , k )
180- ch <- .ch_idx(x , ch )
135+ .df_i <- \(x , k = NULL , ch = NULL , c = NULL ) {
136+ a <- .get_plot_data(x , k )
137+ ch_i <- .ch_idx(x , ch )
138+ if (! .is_rgb(x ))
139+ a <- a [ch_i , , , drop = FALSE ]
140+ dt <- .get_image_dtype(a )
141+ a <- realize(as(a , " DelayedArray" ))
142+ a <- .normalize_image_array(a , dt )
181143 if (! .is_rgb(x ))
182- a <- a [ch , , , drop = FALSE ]
183- dt <- .get_img_dt(a )
184- a <- as(a , " DelayedArray" )
185- a <- .norm_ia(realize(a ), dt )
186- # enter when image isn't RGB already, either
187- # custom colors or contrasts are specified
188- if (! .is_rgb(x ) || ! is.null(c ) || ! is.null(cl ))
189- a <- .chs2rgb(a , ch , c , cl )
144+ a <- .manage_channels(a , ch_i , c )
190145 apply(a , c(2 , 3 ), \(. ) do.call(rgb , as.list(. )))
191146}
192147
@@ -208,13 +163,13 @@ plotSpatialData <- \() ggplot() + scale_y_reverse() + .theme
208163
209164# ' @rdname plotImage
210165# ' @export
211- setMethod ("plotImage ", "SpatialData", \(x, i=1, j=1, k=NULL, ch=NULL, c=NULL, cl=NULL ) {
166+ setMethod ("plotImage ", "SpatialData", \(x, i=1, j=1, k=NULL, ch=NULL, c=NULL) {
212167 if (is.numeric(i ))
213168 i <- imageNames(x )[i ]
214169 y <- image(x , i )
215170 if (is.numeric(j ))
216171 j <- CTname(y )[j ]
217- df <- .df_i(y , k , ch , c , cl )
172+ df <- .df_i(y , k , ch , c )
218173 wh <- .get_wh(x , i , j )
219174 .gg_i(df , wh $ w , wh $ h )
220175})
0 commit comments