-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Refactor geom_contour()? #3044
Comments
One of my personal pet peeves is that library(ggplot2)
set.seed(4393)
dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
d <- ggplot(dsmall, aes(x, y))
# works
d + geom_raster(aes(fill = stat(density)), stat = "density_2d", contour = FALSE) # doesn't work but should in my opinion
d + geom_raster(aes(fill = stat(density)), stat = "density_2d")
#> Don't know how to automatically pick scale for object of type function. Defaulting to continuous.
#> Error in is.finite(x): default method not implemented for type 'closure' Created on 2018-12-21 by the reprex package (v0.2.1) |
The argument for changing the default of the The argument against changing this default is that it will potentially break existing code. One way around this problem may be to soft-deprecate |
One other issue: library(ggplot2)
set.seed(4393)
dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
d <- ggplot(dsmall, aes(x, y))
# works
d + geom_contour(stat = "density_2d") # doesn't work but should
d + geom_contour(aes(fill = stat(level)), stat = "density_2d")
#> Warning: Ignoring unknown aesthetics: fill # works
d + geom_polygon(aes(fill = stat(level)), stat = "density_2d") Created on 2018-12-21 by the reprex package (v0.2.1) |
The problem of filled contours has come up time and time again. I don’t think we should attempt to add support before ggplot2 has native support for holed polygons |
I’m petty sure @hadley has opinions on this as well, if I remember correctly from the last issue that requested this |
I've looked at the prior issues and the output returned by In case anybody is curious, the code for the current implementation is here: |
Instead of trying to understand the poorly documented C code in the base R distribution, it's probably easier to just implement the marching squares algorithm from scratch. A good overview is provided on wikipedia: https://en.wikipedia.org/wiki/Marching_squares |
I realized the refactoring I proposed may not be possible. It's not clear to me how we would map levels in the contours to colors if the contours don't exist until the very end, right before drawing. @thomasp85 @yutannihilation If you agree this would be a problem, then I'll close this issue for now. If you can see a way to work around this issue, please let me know. |
I don't think that is a problem as such. The colour is directly related to the underlying data of the density/height map and really just a binning performed by the geom... There are other issues to be solved for sure, such as what the fill of the band should correspond to (the mean, lower, or upper value of the spanned range) as well as how to achieve the current type of plot with disconnected paths, but they should all be doable... |
Yeah, I've thought through these. I think the geom could take a parameter indicating which value should be used to determine fill. The problem with the binning still concerns me, because the geom itself would have perform the color mapping. In any case I'll take a stab at this kind of a geom, but we may find that it's not appropriate for ggplot2 proper and needs to live in an extension package. |
I'm yet to figure out what the problem is...
Are there any way to bypass scale mapping and keep the raw But, I feel this is going to be hacky, considering there's no formal way for Geoms to affect on Scales. So, probably I'll agree with Claus that "we may find that it's not appropriate for ggplot2 proper." |
Since we have closed #2534, I think filled contours are back on the table for this issue. A first release of the isoband package is on CRAN, so we have the underlying functionality to generate filled contour polygons: https://cran.r-project.org/web/packages/isoband/ Some additional thoughts:
|
labeled contour sounds cool! |
Proof of concept for labeled contour lines. library(isoband) # needs version 0.2.0 from github
library(grid)
x <- (1:ncol(volcano))/(ncol(volcano)+1)
y <- (nrow(volcano):1)/(nrow(volcano)+1)
lines <- isolines(x, y, volcano, 10*(10:18))
# create a colored background
grid.newpage()
grid.rect(width = .8, height = .8, gp = gpar(fill = "azure1", col = NA))
grid.rect(width = .6, height = .6, gp = gpar(fill = "cornsilk1", col = NA))
grid.rect(width = .4, height = .4, gp = gpar(fill = "cornsilk2", col = NA))
grid.rect(width = .2, height = .2, gp = gpar(fill = "cornsilk3", col = NA))
# draw labeled lines
grid.draw(isolines_grob(lines)) Created on 2019-02-05 by the reprex package (v0.2.1) |
@yutannihilation, @thomasp85, and anybody else who would like to chime in: As I mentioned in the previous comment, I'm working on a grob that can draw labeled contour lines. I'm now at the point where the basic infrastructure is in place and the one remaining issue is the correct API, in particular with respect to specifying graphical parameters. I'd like to receive feedback on different options, and I've opened an issue where we can discuss the pros and cons of various approaches: Please take a look and let me know your thoughts. I'd hate to pick an API that'll cause predictable problems down the road. |
@paleolimbot is going to take a look — he'll brainstorm some API ideas for the ggplot2 side, think about whether we can make it a drop in replacement for the existing |
Sounds good. One thing I feel pretty certain about at this time: We'll probably need at least two separate geoms, one for contour lines and one for contour bands, e.g. |
Claus, does your grob work if points are not defined in a regular grid? I'm asking because computing contours at draw time could prove impossible under some coordinate transformations otherwise. I'm thinking of a scalar field defined at a regular longitude by latitude grid but that is then projected into a cartographical projection. |
You have to separate the grob (which only draws lines/polygons but doesn't generate them) from the isolining/isobanding functions which calculate the lines/polygons. The functions that actually calculate the lines/polygons require a regular grid. They will not work on transformed data. For this and other reasons, I feel fairly certain now that the default geoms ( |
I've thought that it could do this, these grids are common in climate models, and usually aren't a transformation, i e there's no regular grid but the index. But, isn't it enough to march on the index, then use real coordinates on the vertices? (I'll make an example) |
Michael, yes, as long as the input can be provided as a regular matrix things should work. Also, the isoband package reconstructs isobands and isolines internally without interpolating coordinates until the very last minute, so it would be fairly straightforward to modify the package to allow for alternative coordinate interpolation approaches if necessary. See here. Point coordinates are calculated at the very end, when we're collecting the final polygons: |
@clauswilke I'm working on this now, and I want to make sure I'm doing something with the output of library(ggplot2)
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_contour(aes(z = density, col = factor(stat(level)))) ggplot(faithfuld, aes(waiting, eruptions)) +
stat_contour(aes(z = density, fill = stat(level)), complete = TRUE, geom = "polygon") Created on 2019-07-12 by the reprex package (v0.2.1) The |
In case you'd like to have a look before the PR, the code is here: master...paleolimbot:issue-3044-isoband-contours |
Yes, what you currently have is approximately what I envisioned for A couple of comments, in no specific order:
|
Thank you! I think I addressed these in the PR, but if you have the time to take a look at #3439 I'd be more than happy to make any changes! |
This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/ |
As discussed on Twitter here and previously explained in a blog post by @thomasp85 an argument can be made that
geom_contour()
should take a 2d density map as input and calculate its own contour lines without using a stat. I'm opening this issue so we can discuss pros and cons of various approaches.I think there is precedent for this kind of refactoring with the refactoring of
geom_bar()
,geom_histogram()
, andgeom_col()
some time back.The text was updated successfully, but these errors were encountered: