hrbrmstr / ggalt

:earth_americas: Extra Coordinate Systems, Geoms, Statistical Transformations & Scales for 'ggplot2'
https://cran.r-project.org/web/packages/ggalt/vignettes/ggalt_examples.html
Other
654 stars 99 forks source link

Blank Plot Output when using "geom_xspline" in ggalt package #60

Open al-obrien opened 5 years ago

al-obrien commented 5 years ago

I recently was trying geom_xspline from the ggalt to replace an existing geom_line in my ggplot object. When using ggarrange and geom_xspline, a blank screen was output and no other plots could be passed through RStudio until the session was restarted. I left a similar post on the ggpubr GitHub page; however, I believe the source of the bug resides in ggalt.

Working Code w/o geom_xspline

library(ggplot2)
library(ggpubr)
myplot = ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_line()
ggarrange(myplot, myplot) # Works and outputs fine

Code using geom_xspline (no RStudio preview panel output)

library(ggalt)
library(ggplot2)
library(ggpubr)
myplot = ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_xspline()
ggarrange(myplot, myplot) # Output becomes blank and freezes the plot panel

Based upon this stack overflow page, the output from ggarrange can still be saved, even though it doesn't display in RStudio.

There is also a proposed solution to address the issue by making adjustments to geom_xspline2. I am not sure if this is a feasible solution to add to ggalt on CRAN but it appears to work with ggarrange in this rough example:

# Create new geom based upon code from ggalt GitHub page
GeomXSpline3 <- ggproto("GeomXSpline3", Geom,
                        required_aes = c("x", "y"),
                        default_aes = aes(colour = "black", shape=-1, open=T),
                        draw_key = draw_key_point,

                        draw_panel = function(data, panel_params, coord) {
                          coords <- coord$transform(data, panel_params)
                          grid::xsplineGrob(
                            coords$x, coords$y,
                            shape = coords$shape, 
                            open = coords$open[1],
                            gp = grid::gpar(col = coords$colour)
                          )
                        }
)

geom_xspline3 <- function(mapping = NULL, data = NULL, stat = "identity",
                          position = "identity", na.rm = FALSE, show.legend = NA,
                          inherit.aes = TRUE, ...) {
  layer(
    geom = GeomXSpline3, mapping = mapping,  data = data, stat = stat,
    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
    params = list(na.rm = na.rm, ...)
  )
}

# Plot with ggarrange
myplot = ggplot(data = mtcars, aes(x = wt, y = mpg)) +
  geom_xspline3(shape = -.25) + geom_point()
ggpubr::ggarrange(myplot, myplot) 

image

al-obrien commented 5 years ago

I made a few changes to the new geom that I suggested above. The changes allow for control over size, line-type, and grouping by aesthetics. I think this is usable across most use-cases, but I haven't tested it too extensively yet. However, I was wondering if this is something that could be included as an update to the existing geom_xspline2 that is hidden in the existing package but isn't entirely functional, to my knowledge. I can fork the package if that is easiest.

GeomXSpline <- ggplot2::ggproto("GeomXSpline", ggplot2::Geom,
                        required_aes = c("x", "y"),
                        default_aes = ggplot2::aes(colour = "black",
                                                   size = 0.5, 
                                                   linetype = 1,
                                                   alpha = 1, 
                                                   spline_shape=-1,
                                                   open=T),

                        draw_key = ggplot2::draw_key_smooth, # controls what is drawn in legend

                        draw_group = function(data, panel_params, coord) {

                          n <- nrow(data)
                          if (n <= 2) return(grid::nullGrob())

                          coords <- coord$transform(data, panel_params)

                          first_row <- coords[1, , drop = FALSE]

                          grid::xsplineGrob(
                            coords$x, coords$y,
                            shape = coords$spline_shape,
                            open = coords$open[1],
                            gp = grid::gpar(col = first_row$colour,
                                            lwd = first_row$size * .pt,
                                            alpha = first_row$alpha,
                                            lty = first_row$linetype)
                          )
                        }
)

geom_xspline <- function(mapping = NULL,
                         data = NULL,
                         stat = "identity",
                         position = "identity",
                         spline_shape = -1,
                         open = T,
                         na.rm = FALSE,
                         show.legend = NA,
                         inherit.aes = TRUE,
                         ...) {
  layer(
    geom = GeomXSpline,
    mapping = mapping,
    data = data,
    stat = stat,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(spline_shape = spline_shape,
                  open = open,
                  na.rm = na.rm,
                  ...)
  )
}