Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geom_contour documentation is misleading #4324

Closed
dmurdoch opened this issue Jan 24, 2021 · 11 comments · Fixed by #4325
Closed

geom_contour documentation is misleading #4324

dmurdoch opened this issue Jan 24, 2021 · 11 comments · Fixed by #4325

Comments

@dmurdoch
Copy link
Contributor

dmurdoch commented Jan 24, 2021

The documentation for geom_contour says:

Contouring
tends to work best when \code{x} and \code{y} form a (roughly) evenly
spaced grid.

but in fact, as issue #4320 and its discussion describes, there are much more stringent requirements. Exactly what the requirements are is a little unclear to me; the code to do it is in isoband_z_matrix() here:

isoband_z_matrix <- function(data) {
It's something like "Contouring requires the (x, y) pairs to be a large subset of the grid of all possible pairs of unique values of x and y, with no repeats."

It would also be helpful to add an example using akima::interp(), the usual way to produce the grid of values from irregular data.

@clauswilke
Copy link
Member

As I said in #4320, the true condition is that you have a matrix of z values whose locations can be identified with marginal vectors of x and y values. It's Ok for some z values to be missing, though, as long as there are corresponding NAs in the matrix of z values.

I agree the documentation should spell this out clearly.

@dmurdoch
Copy link
Contributor Author

I think your description is too strict. For example, this works:

# First, start with a complete grid
df <- expand.grid(x=1:10, y=1:10)
df$z <- with(df, x^2 + y^2)

# Take the subset of lower z values
df <- subset(df, z < 100)

# Shuffle it
df <- df[sample(nrow(df)),]

head(df)
#>    x y  z
#> 37 7 4 65
#> 42 2 5 29
#> 52 2 6 40
#> 34 4 4 32
#> 7  7 1 50
#> 1  1 1  2
library(ggplot2)
ggplot(df, aes(x, y, z=z)) + geom_contour()

Created on 2021-01-24 by the reprex package (v0.3.0)

@clauswilke
Copy link
Member

I'm pretty sure what's happening is that ggplot2 expands this input into a matrix of z values whose locations can be identified with marginal vectors of x and y values, replacing missing values with NA. Because that's the input that the isoband algorithm requires. I would know, I wrote it. :-)

This also explains what happens with the rotated input data: ggplot2 turns it into a grid of all possible combinations of x and y, inserting NAs where needed, and then isoband never has enough of a consecutive region of non-NA data to actually generate any contours at all, and you end up with no contours.

@dmurdoch
Copy link
Contributor Author

Yes, that's what happens; I was just quibbling about your original description of it.

The description in your most recent comment seems accurate, but is still incomplete: it covers the creation of the z matrix clearly, but it's still a little unclear to me how the algorithm handles missing z values when computing the isolines. Does it need all 4 corners of a grid cell to be non-missing, or would 3 corners be enough? Surely at least 3 are needed.

And there's still the issue of deciding on the balance between clarity and exact detailed correctness in the docs.

@clauswilke
Copy link
Member

For any square in the grid, if there's at least one point that has a z value of NA then the entire square is ignored. This means NAs can remove fairly large areas from the isolines or isobands.

library(isoband)

m <- matrix(
  c(NA, NA, NA, 0, 0, 0,
    NA, NA, NA, 1, 1, 0,
    0,  0,  1, 1, 1, 0,
    0,  1,  1, 0, 0, 0,
    0,  0,  0, 1, 0, 0,
    0,  0,  0, 0, 0, 0),
  6, 6, byrow = TRUE
)
plot_iso(m, 0.5, 1.5)

Created on 2021-01-24 by the reprex package (v0.3.0)

@dmurdoch
Copy link
Contributor Author

Okay, so how about this text to replace the current Description section:

ggplot2 can not draw true 3D surfaces, but you can use geom_contour(), geom_contour_filled(), and geom_tile() to visualise 3D surfaces in 2D. To specify a valid surface, the data must contain x,y, and z coordinates, and each unique combination of x and y can appear at most once. Contouring requires that the points can be rearranged so that the z values form a matrix, with rows corresponding to unique x values, and columns corresponding to unique y values. Missing entries are allowed, but contouring will only be done on cells of the grid with all four z values present. If your data is irregular, you can interpolate to a grid before visualising using the akima::interp function.

@clauswilke
Copy link
Member

I think this is good, except at the very end I'd write "using the interp function from the akima package", to make clear this is not a function provided by ggplot2.

Do you want to prepare a PR?

@dmurdoch
Copy link
Contributor Author

Sure, I'll put in a PR, but I'd like to include an example using akima::interp. Is it going to be accepted to add yet another suggested package?

@clauswilke
Copy link
Member

That's a question for @thomasp85.

@cneyens
Copy link

cneyens commented Jan 26, 2021

Please be aware that akima uses a non-commercial ACM license (see also here). The package interp can be used as an alternative although I've had cases where interp::interp fails when akima::interp doesn't. Also note that these interp functions are intended for input points that are not collinear.

@dmurdoch
Copy link
Contributor Author

@cneyens: Thanks! I've used interp, but I didn't realize that was its motivation. I'll switch the advice and example to use it instead of akima.

yutannihilation pushed a commit that referenced this issue Jan 30, 2021
* Improve docs for geom_contour as discussed in issue #4324

* Stop default testing of new example.

* Recommend interp instead of akima
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants