ANTsX / ANTsRCore

Rcpp bindings for the C++ ANTs library used by the ANTsR package
9 stars 9 forks source link

NA/NaN values writing out #124

Open muschellij2 opened 4 years ago

muschellij2 commented 4 years ago

Describe the bug Similar to #91, reading and writing out NA or NaN values are not handled well in antsImage objects, which is a major issue for most analyses, as NA values are implicitly turned to 0 with no warning or message. Related to https://github.com/muschellij2/extrantsr/issues/14 and https://github.com/jonclayden/RNifti/issues/21

To Reproduce

suppressPackageStartupMessages(library(neurobase))
suppressPackageStartupMessages(library(RNifti))
suppressPackageStartupMessages(library(ANTsRCore))
mask_file = MNITemplate::getMNIPath("Brain_Mask")
binary_mask = antsImageRead(mask_file)
binary_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1 
#>   Filename           : /Library/Frameworks/R.framework/Versions/4.0/Resources/library/MNITemplate/extdata/MNI152_T1_1mm_Brain_Mask.nii.gz

Adding in NA

NO CLONING

na_mask = binary_mask
na_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1 
#>   Filename           : /Library/Frameworks/R.framework/Versions/4.0/Resources/library/MNITemplate/extdata/MNI152_T1_1mm_Brain_Mask.nii.gz

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

but we see it turns to NaN

c(na_mask[1,1,1:3])
#> [1] NaN   0   0

but again as we didn’t clone, it changes binary_mask!
The average user may not know this

c(binary_mask[1,1,1:3])
#> [1] NaN   0   0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1] NaN NaN   0
c(binary_mask[1,1,1:3])
#> [1] NaN NaN   0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

WIth Cloning

binary_mask = antsImageRead(mask_file)
na_mask = antsImageClone(binary_mask)
na_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

but we see it turns to NaN

c(na_mask[1,1,1:3])
#> [1] NaN   0   0

but again as did clone, it doesn’t changes binary_mask!

c(binary_mask[1,1,1:3])
#> [1] 0 0 0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1] NaN NaN   0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

Try with Double

We will clone as we have shown above that’s the way to do it.

binary_mask = antsImageRead(mask_file)
na_mask = antsImageClone(binary_mask, out_pixeltype = "double")
na_mask
#> antsImage
#>   Pixel Type          : double 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

does NOT turn to NaN with double - good to document!

c(na_mask[1,1,1:3])
#> [1] NA  0  0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1]  NA NaN   0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

Issues with Writing NA in binary data

tfile = tempfile(fileext = ".nii.gz")
antsImageWrite(na_mask, tfile)

After reading back in, no NA/NaN values are there

reread = antsImageRead(tfile)
c(reread[1,1,1:3])
#> [1] 0 0 0

But RNifti seems fine:

RNifti::readNifti(tfile)[1,1,1:3]
#> [1]  NA NaN   0

as does neurobase

neurobase::readnii(tfile)[1,1,1:3]
#> [1]  NA NaN   0

Trying Int Data

I know I keep the names of binary and such, but this is really integer data

mask_file = MNITemplate::getMNIPath(what = "T1")
binary_mask = antsImageRead(mask_file)
hist(binary_mask)

binary_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1 
#>   Filename           : /Library/Frameworks/R.framework/Versions/4.0/Resources/library/MNITemplate/extdata/MNI152_T1_1mm.nii.gz

Adding in NA

NO CLONING

na_mask = binary_mask
na_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1 
#>   Filename           : /Library/Frameworks/R.framework/Versions/4.0/Resources/library/MNITemplate/extdata/MNI152_T1_1mm.nii.gz

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

but we see it turns to NaN

c(na_mask[1,1,1:3])
#> [1] NaN   0   0
c(binary_mask[1,1,1:3])
#> [1] NaN   0   0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1] NaN NaN   0
c(binary_mask[1,1,1:3])
#> [1] NaN NaN   0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

WIth Cloning

binary_mask = antsImageRead(mask_file)
na_mask = antsImageClone(binary_mask)
na_mask
#> antsImage
#>   Pixel Type          : float 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

but we see it turns to NaN

c(na_mask[1,1,1:3])
#> [1] NaN   0   0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1] NaN NaN   0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

Try with Double

We will clone

binary_mask = antsImageRead(mask_file)
na_mask = antsImageClone(binary_mask, out_pixeltype = "double")
na_mask
#> antsImage
#>   Pixel Type          : double 
#>   Components Per Pixel: 1 
#>   Dimensions          : 182x218x182 
#>   Voxel Spacing       : 1x1x1 
#>   Origin              : -90 126 -72 
#>   Direction           : 1 0 0 0 -1 0 0 0 1

Adding in NA gives na error

na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
c(na_mask[1,1,1:3])
#> [1] 0 0 0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

As the data type is integer, you need to be explicit about NA

na_mask[1,1,1] = NA_integer_

does NOT turn to NaN with double - good to document!

c(na_mask[1,1,1:3])
#> [1] NA  0  0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0

NaN is fine

na_mask[1,1,2] = NaN

NaN is fine

c(na_mask[1,1,1:3])
#> [1]  NA NaN   0
c(binary_mask[1,1,1:3])
#> [1] 0 0 0
class(na_mask)
#> [1] "antsImage"
#> attr(,"package")
#> [1] "ANTsRCore"

Issues with Writing NA in binary data

tfile = tempfile(fileext = ".nii.gz")
antsImageWrite(na_mask, tfile)

After reading back in, no NA/NaN values are there

reread = antsImageRead(tfile)
c(reread[1,1,1:3])
#> [1] 0 0 0

But RNifti seems fine:

RNifti::readNifti(tfile)[1,1,1:3]
#> [1]  NA NaN   0

as does neurobase

neurobase::readnii(tfile)[1,1,1:3]
#> [1]  NA NaN   0

Created on 2020-09-04 by the reprex package (v0.3.0)

Session info ``` r devtools::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.0.2 (2020-06-22) #> os macOS Mojave 10.14.6 #> system x86_64, darwin17.0 #> ui X11 #> language (EN) #> collate en_US.UTF-8 #> ctype en_US.UTF-8 #> tz America/New_York #> date 2020-09-04 #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> package * version date lib #> abind 1.4-5 2016-07-21 [1] #> ANTsRCore * 0.7.4.6 2020-07-07 [1] #> assertthat 0.2.1 2019-03-21 [1] #> backports 1.1.9 2020-08-24 [1] #> bitops 1.0-6 2013-08-17 [1] #> callr 3.4.3 2020-03-28 [1] #> cli 2.0.2 2020-02-28 [1] #> crayon 1.3.4 2017-09-16 [1] #> curl 4.3 2019-12-02 [1] #> desc 1.2.0 2020-06-01 [1] #> devtools 2.3.1.9000 2020-08-25 [1] #> digest 0.6.25 2020-02-23 [1] #> ellipsis 0.3.1 2020-05-15 [1] #> evaluate 0.14 2019-05-28 [1] #> fansi 0.4.1 2020-01-08 [1] #> fs 1.5.0 2020-07-31 [1] #> glue 1.4.1 2020-05-13 [1] #> highr 0.8 2019-03-20 [1] #> htmltools 0.5.0 2020-06-16 [1] #> httr 1.4.2 2020-07-20 [1] #> ITKR 0.5.3.2.0 2020-06-01 [1] #> knitr 1.29 2020-06-23 [1] #> lattice 0.20-41 2020-04-02 [1] #> lifecycle 0.2.0 2020-03-06 [1] #> magrittr 1.5 2014-11-22 [1] #> Matrix 1.2-18 2019-11-27 [1] #> matrixStats 0.56.0 2020-03-13 [1] #> memoise 1.1.0 2017-04-21 [1] #> mime 0.9 2020-02-04 [1] #> MNITemplate 1.0.0 2020-06-01 [1] #> neurobase * 1.31.0 2020-09-04 [1] #> oro.nifti * 0.11.0 2020-09-04 [1] #> pkgbuild 1.1.0 2020-07-13 [1] #> pkgload 1.1.0 2020-05-29 [1] #> prettyunits 1.1.1 2020-01-24 [1] #> processx 3.4.3 2020-07-05 [1] #> ps 1.3.4 2020-08-11 [1] #> purrr 0.3.4 2020-04-17 [1] #> R.methodsS3 1.8.0 2020-02-14 [1] #> R.oo 1.23.0 2019-11-03 [1] #> R.utils 2.9.2 2019-12-08 [1] #> R6 2.4.1 2019-11-12 [1] #> Rcpp 1.0.5 2020-07-06 [1] #> RcppEigen 0.3.3.7.0 2019-11-16 [1] #> remotes 2.2.0 2020-07-21 [1] #> rlang 0.4.7.9000 2020-08-25 [1] #> rmarkdown 2.3 2020-06-18 [1] #> RNifti * 1.2.0 2020-08-25 [1] #> rprojroot 1.3-2 2018-01-03 [1] #> sessioninfo 1.1.1 2018-11-05 [1] #> stringi 1.4.6 2020-02-17 [1] #> stringr 1.4.0 2019-02-10 [1] #> testthat 2.99.0.9000 2020-08-25 [1] #> usethis 1.6.1.9001 2020-08-25 [1] #> withr 2.2.0 2020-04-20 [1] #> xfun 0.16 2020-07-24 [1] #> xml2 1.3.2 2020-04-23 [1] #> yaml 2.2.1 2020-02-01 [1] #> source #> CRAN (R 4.0.0) #> Github (muschellij2/ANTsRCore@61c37a1) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> Github (muschellij2/desc@b0c374f) #> Github (r-lib/devtools@df619ce) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> Github (stnava/ITKR@9bdd5f8) #> CRAN (R 4.0.2) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> Github (muschellij2/MNITemplate@46e8f81) #> local #> local #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> Github (r-lib/rlang@de0c176) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> Github (r-lib/testthat@6a24275) #> Github (r-lib/usethis@860c1ea) #> CRAN (R 4.0.0) #> CRAN (R 4.0.2) #> CRAN (R 4.0.0) #> CRAN (R 4.0.0) #> #> [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library ```

Session Info

Please include output from R of:

ANTsRCore::antsVersions
#>   Dependency                                   GitTag
#> 1       ANTs 8c61a430099e9d5ba580b7255132cfa58a7ee880
#> 2  ANTsRCore                                         
#> 3    ANTsURL        https://github.com/ANTsX/ANTs.git
#> 4        ITK 1e708db2f586997e408cfdc2cea5114ae5575892
sessioninfo::session_info("ANTsRCore")
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 4.0.2 (2020-06-22)
#>  os       macOS Mojave 10.14.6        
#>  system   x86_64, darwin17.0          
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2020-09-04                  
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package   * version   date       lib source                                
#>  ANTsRCore   0.7.4.6   2020-07-07 [1] Github (muschellij2/ANTsRCore@61c37a1)
#>  ITKR        0.5.3.2.0 2020-06-01 [1] Github (stnava/ITKR@9bdd5f8)          
#>  lattice     0.20-41   2020-04-02 [1] CRAN (R 4.0.2)                        
#>  magrittr    1.5       2014-11-22 [1] CRAN (R 4.0.0)                        
#>  Matrix      1.2-18    2019-11-27 [1] CRAN (R 4.0.2)                        
#>  Rcpp        1.0.5     2020-07-06 [1] CRAN (R 4.0.0)                        
#>  RcppEigen   0.3.3.7.0 2019-11-16 [1] CRAN (R 4.0.0)                        
#> 
#> [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library