ggplot2 icon indicating copy to clipboard operation
ggplot2 copied to clipboard

`geom_raster`can produce an error when aesthetics are set to floating-point values.

Open alexgenin opened this issue 6 years ago • 8 comments

When using floating-point values as x/y aesthetics in geom_raster, I sometimes get the following error (and additional warning):

library(ggplot2)

data_error <- structure(list(bw = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.22222222222222, 
  1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 
  1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 
  1.22222222222222, 1.44444444444444, 1.44444444444444, 1.44444444444444, 
  1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 
  1.44444444444444, 1.44444444444444, 1.44444444444444, 1.66666666666667, 
  1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 
  1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 
  1.66666666666667, 1.88888888888889, 1.88888888888889, 1.88888888888889, 
  1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 
  1.88888888888889, 1.88888888888889, 1.88888888888889, 2.11111111111111, 
  2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 
  2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 
  2.11111111111111, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
  2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
  2.33333333333333, 2.33333333333333, 2.33333333333333, 2.55555555555556, 
  2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 
  2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 
  2.55555555555556, 2.77777777777778, 2.77777777777778, 2.77777777777778, 
  2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 
  2.77777777777778, 2.77777777777778, 2.77777777777778, 3, 3, 3, 3, 3, 3, 
  3, 3, 3, 3), cutoff = c(0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1), ncomp = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("bw", "cutoff", 
  "ncomp"), class = "data.frame", row.names = c(NA, -100L))

data_ok <- data.frame(expand.grid(bw = seq(1, 3, length.out = 10), cutoff = seq(0, 
  1, length.out = 10)))
data_ok <- data_ok[order(data_ok$bw, data_ok$cutoff), ]
data_ok[, "ncomp"] <- data_error[, "ncomp"]

row.names(data_error) <- row.names(data_ok) <- NULL

# The two data.frames seem to be equal
all.equal(data_ok, data_error)
#> [1] TRUE

# ...but this produces an error
ggplot(data_error) + geom_raster(aes(x = bw, y = cutoff, fill = ncomp))
#> Warning in f(...): NAs introduced by coercion to integer range
#> Error in matrix(NA_character_, nrow = nrow, ncol = ncol): invalid 'nrow' value (too large or NA)

# ...and this is ok
ggplot(data_ok) + geom_raster(aes(x = bw, y = cutoff, fill = ncomp))


# The problem can be fixed by rounding
ggplot(data_error) + geom_raster(aes(x = round(bw, 10), y = round(cutoff, 10), 
  fill = ncomp))

alexgenin avatar Apr 10 '18 10:04 alexgenin

Would you mind turning this into a reprex (short for minimal reproducible example)? It's especially helpful for ggplot2, since it automatically generates and uploads the plots (or lack thereof), which makes it much easier to go through at a glance.

If you've never heard of a reprex before, you might want to start by reading the tidyverse.org help page.

Right now the best way to install reprex is:

# install.packages("devtools")
devtools::install_github("tidyverse/reprex")

If you run into problems with access to your clipboard, you can specify an outfile for the reprex, and then copy and paste (or drag and drop) the contents here.

reprex::reprex(input = "fruits_stringdist.R", outfile = "fruits_stringdist.md")

Thanks.

batpigandme avatar Apr 10 '18 10:04 batpigandme

Hello, no problem. Below is the output from reprex().

Thanks

library(ggplot2)

data_error <- structure(list(bw = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.22222222222222, 
  1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 
  1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 
  1.22222222222222, 1.44444444444444, 1.44444444444444, 1.44444444444444, 
  1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 
  1.44444444444444, 1.44444444444444, 1.44444444444444, 1.66666666666667, 
  1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 
  1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 
  1.66666666666667, 1.88888888888889, 1.88888888888889, 1.88888888888889, 
  1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 
  1.88888888888889, 1.88888888888889, 1.88888888888889, 2.11111111111111, 
  2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 
  2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 
  2.11111111111111, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
  2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
  2.33333333333333, 2.33333333333333, 2.33333333333333, 2.55555555555556, 
  2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 
  2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 
  2.55555555555556, 2.77777777777778, 2.77777777777778, 2.77777777777778, 
  2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 
  2.77777777777778, 2.77777777777778, 2.77777777777778, 3, 3, 3, 3, 3, 3, 
  3, 3, 3, 3), cutoff = c(0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
  0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 
  0.888888888888889, 1), ncomp = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("bw", "cutoff", 
  "ncomp"), class = "data.frame", row.names = c(NA, -100L))

data_ok <- data.frame(expand.grid(bw = seq(1, 3, length.out = 10), cutoff = seq(0, 
  1, length.out = 10)))
data_ok <- data_ok[order(data_ok$bw, data_ok$cutoff), ]
data_ok[, "ncomp"] <- data_error[, "ncomp"]

row.names(data_error) <- row.names(data_ok) <- NULL

# The two data.frames seem to be equal
all.equal(data_ok, data_error)
#> [1] TRUE

# ...but this produces an error
ggplot(data_error) + geom_raster(aes(x = bw, y = cutoff, fill = ncomp))
#> Warning in f(...): NAs introduced by coercion to integer range
#> Error in matrix(NA_character_, nrow = nrow, ncol = ncol): invalid 'nrow' value (too large or NA)

# ...and this is ok
ggplot(data_ok) + geom_raster(aes(x = bw, y = cutoff, fill = ncomp))


# The problem can be fixed by rounding
ggplot(data_error) + geom_raster(aes(x = round(bw, 10), y = round(cutoff, 10), 
  fill = ncomp))

alexgenin avatar Apr 19 '18 10:04 alexgenin

For what it's worth, I am experiencing the same error with the following data.

library(tidyverse)

data = crossing(
    x = seq(-1, 1, by = 0.01), 
    a = seq(1, 5, by = 0.01)
  ) %>%
  mutate(y = a*x^2)

Rounding the variables in the ggplot mapping, as mentioned here, works.

buggaby avatar Jan 09 '19 22:01 buggaby

@buggaby Thanks, but it seems your data is not suitable for geom_raster(), which expects

geom_raster() is a high performance special case for when all the tiles are the same size.

yutannihilation avatar Jan 10 '19 00:01 yutannihilation

The error comes from here:

https://github.com/tidyverse/ggplot2/blob/9eae13b3d17bde26cf9df649887b4a6bb2ac92ce/R/geom-raster.r#L72-L79

I found the very small jitterings in data cause NA.

data_error <- structure(
  list(
    bw = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.22222222222222, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.44444444444444, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.66666666666667, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 1.88888888888889, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.11111111111111, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.55555555555556, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 2.77777777777778, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
    cutoff = c(0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555555, 0.666666666666667, 0.777777777777778, 0.888888888888889, 1),
    ncomp = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
  ),
  .Names = c("bw", "cutoff", "ncomp"),
  class = "data.frame", row.names = c(NA, -100L)
)

a1 <- 1 / 9
data1 <- expand.grid(
  x = 1 + 2 * a1 * 0:9,
  y = a1 * 0:9,
  KEEP.OUT.ATTRS = FALSE
)

data1 <- dplyr::arrange(data1, x, y)

# although they are considered all equal, slightly different
all.equal(data_error$cutoff, data1$y)
#> [1] TRUE

data_error$cutoff - data1$y
#>   [1]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>   [6]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [11]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [16]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [21]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [26] -5.551115e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [31]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [36]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [41]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [46]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [51]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [56]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [61]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [66]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [71]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [76] -5.551115e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [81]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [86]  4.440892e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00
#>  [91]  0.000000e+00 -1.110223e-16 -2.220446e-16 -3.330669e-16 -4.440892e-16
#>  [96] -5.551115e-16  3.330669e-16  3.330669e-16  1.110223e-16  0.000000e+00

Created on 2019-01-10 by the reprex package (v0.2.1)

Since the result of resolution() is too small, (data1$y - min(data1$y)) / resolution(data1$y, FALSE) is larger than the max of integer, so as.integer() returns NA. I think the resolution must be "rounded" into the range of integer, but I don't have nice idea for now.

library(ggplot2)

a1 <- 1 / 9
data1 <- expand.grid(
  x = 1 + 2 * a1 * 0:9,
  y = a1 * 0:9,
  KEEP.OUT.ATTRS = FALSE
)

data1 <- dplyr::arrange(data1, x, y)

# add some values
data1$y[c(26, 76, 96)] <- data1$y[c(26, 76, 96)] - 9.992007e-16

resolution(data1$y, FALSE)
#> [1] 9.992007e-16

as.integer((data1$y - min(data1$y)) / resolution(data1$y, FALSE))
#> Warning: NAs introduced by coercion to integer range
#>   [1]  0 NA NA NA NA NA NA NA NA NA  0 NA NA NA NA NA NA NA NA NA  0 NA NA
#>  [24] NA NA NA NA NA NA NA  0 NA NA NA NA NA NA NA NA NA  0 NA NA NA NA NA
#>  [47] NA NA NA NA  0 NA NA NA NA NA NA NA NA NA  0 NA NA NA NA NA NA NA NA
#>  [70] NA  0 NA NA NA NA NA NA NA NA NA  0 NA NA NA NA NA NA NA NA NA  0 NA
#>  [93] NA NA NA NA NA NA NA NA

Created on 2019-01-10 by the reprex package (v0.2.1)

yutannihilation avatar Jan 10 '19 00:01 yutannihilation

A shot in the dark. At the last step, replace as.integer with something like:

integerate <- function(x) ifelse(x > .Machine$integer.max, round(x), as.integer(x))
.Machine$integer.max
## [1] 2147483647
integerate(2147483647)
## [1] 2147483647
integerate(2147483648)
## [1] 2147483648
integerate(2147483647.4)
## [1] 2147483647
integerate(2147483647.5)
## [1] 2147483648

ptoche avatar Jan 10 '19 04:01 ptoche

It saves us from the errors, but the some part of the raster will get lost then...

We should not shave the raster, but lower the resolution instead. For example:

reso <- max(resolution(data1$y, FALSE),
            1 / .Machine$integer.max)

as.integer((data1$y - min(data1$y)) / reso)

But, this is not nice. I believe the cutoff's reslution should be 0.111111111111111.

yutannihilation avatar Jan 10 '19 13:01 yutannihilation

Hi, is there a solution for this error yet? Is there a way to modify my data minimally to avoid the error? Thanks in advance.

nfancy avatar Sep 05 '22 09:09 nfancy