daattali / ggExtra

📊 Add marginal histograms to ggplot2, and more ggplot2 enhancements
http://daattali.com/shiny/ggExtra-ggMarginal-demo/
Other
383 stars 45 forks source link

Marg map retry #66

Closed crew102 closed 6 years ago

crew102 commented 7 years ago

This PR implements the feature mentioned in #61. Two notes:

  1. I had to hard-code the size of the lines that cover up the outline created by geom_density here:

https://github.com/crew102/ggExtra/blob/0d9579743824b4a6d23655a43a4275ed4d3fb7b9/R/ggMarginalHelpers.R#L167-L172

The size of the covering line(s) has to be a little bit bigger than the size of the line used by geom_density to actually cover the line on some graphics devices (e.g., svg and pdf in some cases).

  1. I will update the docs after this this PR is merged.
crew102 commented 7 years ago

I will update/rebase this PR sometime this week.

daattali commented 7 years ago

Alright, you fixed the tests :tada:

So this PR can resume.. some conflicts need to be resolved

crew102 commented 6 years ago

Hey Dean, I've been meaning to get back on ggExtra (I'll probably do some work on it later this week). Do you care if I address this issue (i.e., updating conflicts in this branch so it can be merged) before addressing #81? I expect #81 will take much longer to fix.

daattali commented 6 years ago

Sure! I've been 100% absent from all the R packages for the past 2 months so it's ok

crew102 commented 6 years ago

Re: API

p <- ggplot(data = mtcars) +
        geom_point(ggplot2::aes(x = wt, y = drat))

ggMarginal(p, marginMapping = c(fill = TRUE, colour = FALSE))

...because there is no fill mapped in the scatter plot. We don't allow this kind of "custom variable mapping" in the marginal plots b/c then we'd have to deal with manipulating/adding legends to the plot.

Re: documentation

Re: use of utils::globalVariables("var") in margPlotNoGeom()

Re: updated test figs

daattali commented 6 years ago

Thanks Chris, is this ready for review?

crew102 commented 6 years ago

Yep, ready to go. Apologies for the long-winded comment.

daattali commented 6 years ago

Thanks Chris!

I tried it out, and it does seem to work, looks great!

I'll start with the smaller comments:

The bigger comments:

I don't think marginMapping = c(fill = FALSE, colour = FALSE) makes the most sense. If these are the only two allowed values, and you have to know to spell them correctly, I feel it'd be better to take advantage of autocomplete and be more explicit and make two parameters, one for fill and one for colour.

I also don't think it makes sense to allow both fill and colour together when they are mapped to different variables, because the result confusing and too messy to be useful. Some plot types like histogram look really strange when there is only colour but not fill. It also feels a bit awkward that the fill mapping form the original plot has to correspond to the fill of the marginal plot, and same for colour. I'd imagine a common scenario would be to use fill for the points on the original plot but then you wouldn't be able do a grouped marginal that only has a colour without a fill. I strongly believe only one mapping should be used for the marginal plot grouping. Let me know your thoughts

crew102 commented 6 years ago

Hey Dean, thanks for your comments. I've addressed each below.

  1. To answer one of your questions: should we handle the case of "color" vs "colours"? I don't think that's important enough to care about.

OK sounds good.

  1. I don't think marginMapping = c(fill = FALSE, colour = FALSE) makes the most sense. If these are the only two allowed values, and you have to know to spell them correctly, I feel it'd be better to take advantage of autocomplete and be more explicit and make two parameters, one for fill and one for colour.

Agreed. I will change this. We'll use marginFill and marginColour params instead of marginMapping param.

  1. The current parameter seems to result in errors if only fill = TRUE is specified while colour is omitted, or if you don't type colour correctly.

That's b/c the implementation was expecting a length two bool vector for marginMapping param. This won't be a problem when we change over to use marginFill and marginColour params.

  1. The fill colour for histograms is much darker for regular ggMarginal than where there are groupings (I can provide code/screenshots if that's unclear)

You can check out the notes under "Re: updated test figs" for why this is happening. Specifically:

FYI: marginal histograms are still filled with a grey (albeit a bit darker than usual) in this PR's version of ggMarginal(), as ggplot2 fills histograms with dark grey if no fill is specified.

  1. I also don't think it makes sense to allow both fill and colour together when they are mapped to different variables, because the result confusing and too messy to be useful...I strongly believe only one mapping should be used for the marginal plot grouping.

Hmmm, I agree that it can seem like a bit much when fill and colour are mapped to different vars, but I think the user should be able to make this decision (i.e., whether they think it is too messy to map both the vars and they just want to map one aesthetic in the marginal plots). For example, ggplot2 wouldn't tell its users that they're not allowed to map fill, colour, and shape all at the same time, even though it's probably never a good idea to do so. Also, I can tell what's going on in this graph (though it's true that this is kinda an edge case when you don't have too many different groups in colour or fill, so it's not terribly messy):

## in ggExtra dir at tip of marg-map-retry branch

source("tests/testthat/helper-funs.R")

# am var will be mapped to fill, and vs var will be mapped to colour. 
# for example, in the top marginal plot, the two distributions with the smallest
# central tendencies are filled with pink (am = 1), while the two dists with 
# largest means are filled with orange (am = 0). Meanwhile, the values of 
# vs are clear for each of the four distributions (vs = 1 is red line,
# vs = 0 is green line)

funList$`col and fill mapped`()

1

  1. Some plot types like histogram look really strange when there is only colour but not fill.

This is b/c the histogram are stacked by default (as per ggplot2). I've never liked stacked histograms, but I don't think we should try to implement some other positioning (e.g., "identity") b/c there are issues with those as well. For example, see the histogram that I plotted in #61.

Here's an example of just mapping colour to the marginal histogram plot:

library(ggplot2)
library(ggExtra)

p <- ggplot(mtcars) + 
  geom_point(aes(x = wt, y = mpg, colour = factor(gear)))

ggMarginal(
  p, type = "histogram", marginMapping = c(fill = F, colour = T), fill = "white"
)

2

Note that they can add fill to this if they want:

p <- ggplot(mtcars) + 
  geom_point(aes(x = wt, y = mpg, colour = factor(gear), fill = factor(gear)))

ggMarginal(p, type = "histogram", marginMapping = c(fill = T, colour = T))

3

Again, even though it looks better to have both colour and fill mapped, I don't think we should impose any rules on the user that force them to make common-sense choices (i.e., map colour and fill for histograms, not just colour).

  1. It also feels a bit awkward that the fill mapping form the original plot has to correspond to the fill of the marginal plot, and same for colour. I'd imagine a common scenario would be to use fill for the points on the original plot but then you wouldn't be able do a grouped marginal that only has a colour without a fill.

I think the more common situation will be that the user maps colour in the scatter plot (note that this actually fills the points with the colour...You would use fill if you want to do a point with an inner-colour fill) and they want to map either colour or fill to the marginal plots.

They can map colour doing this:

p <- ggplot(mtcars) + 
  geom_point(aes(x = wt, y = mpg, colour = factor(gear)))

ggMarginal(p, type = "density", marginMapping = c(fill = F, colour = T))

8

and fill doing this:

p <- ggplot(mtcars) + 
  geom_point(aes(x = wt, y = mpg, colour = factor(gear), fill = factor(gear)))

ggMarginal(p, type = "density", marginMapping = c(fill = T, colour = F))

9

or both colour and fill:

p <- ggplot(mtcars) + 
  geom_point(aes(x = wt, y = mpg, colour = factor(gear), fill = factor(gear)))

ggMarginal(p, type = "density", marginMapping = c(fill = T, colour = T))

10

daattali commented 6 years ago

I think the param name should not be marginFill/marginColour - that's not informative and actually a bit misleading, because it suggests this will be the fill/colour of the marginal plots. What these params are doing is decide what mapping to use for grouping in the marginal plots. So I think the word "group" or "grouping" should be in the param name.

Ideally I would agree with you that it's not good to remove user flexibility, so yes the user should be able to choose to map both colour and fill. But to me when there is both fill and colour, and they're different, it's very easy to see and understand the filled shapes, but the "colour" which is just a thin outline gets swallowed in the image and it very hard to make out, to the point that I think it doesn't add enough value to warrant supporting both. But if you feel strongly about being able to do both, then ok.

What's more important in my opinion is that the user has to be able to do that case that I mention/you corrected: use one mapping in the scatterplot, but the other mapping in the marginal groups.

crew102 commented 6 years ago

OK re: param names. I'll add group in there somewhere.

I think the most common use case will be the user has mapped a variable to colour in the scatter plot, and wants to map the same variable to either colour or fill (or both) in the marginal plots. That would be possible with the current implementation (see last three graphs in my last post).

What's more important in my opinion is that the user has to be able to do that case that I mention/you corrected: use one mapping in the scatterplot, but the other mapping in the marginal groups.

Just to clarify, are you talking about mapping colour in the scatter plot and fill in the marginal plots? That is supported as in the second to last graph. The user just has to specify fill in the scatter plot.

The reason why I don't think it's a good idea to allow the user to pass variable names into the marginfill/margincolour params is that I think people will assume they can just choose any variable they want, when in fact that variable has to already to mapped in the scatter plot. Having the param be a boolean makes it clearer (at least to me) that this mapping is not going to behave like typical ggplot2 mappings.

daattali commented 6 years ago

I think the most common use case will be the user has mapped a variable to colour in the scatter plot, and wants to map the same variable to either colour or fill (or both) in the marginal plots. That would be possible with the current implementation (see last three graphs in my last post).

I agree that's likely a common usage. But as those last 3 plots show, in order to have the marginal plot show the colour as a fill , the user would have to map the fill variable in the original plot. That's the inflexibility that I think is too limiting - that fill from the scatterplot gets assigned to the fill in the marginal grouping, and same for colour. I'd want to be able to just specify a colour in the scatterplot, and use that grouping for fill in the density plot. Does that make sense? Sorry I don't seem to be as clear as I want to be :)

crew102 commented 6 years ago

OK, how about we only allow the user to map colour from the scatter plot to either colour or fill in the marginal plots? Otherwise we have to take the mapping arguments as strings, which I don't like for the reason mentioned above (and it also makes the implementation more messy/hacky, which could potentially raise issues in the future)

daattali commented 6 years ago

Yeah I also wasn't sure how it'd be possible to implement that without being extremely messy and having a very awkward API. Yes colour from scatterplot should be mappable to either colour or fill in margins. And fill from scatterplot should also be mappable to either colour or fill in the margins, correct?

crew102 commented 6 years ago

Only colour will be mappable (to colour or fill ,or both) in the marginal plots. To allow colour and fill to be mappable would allow the messy graphs that we talked about earlier. If you want both to be mappable, then we should use the API that I originally proposed (except using two bool params instead of one bool vector)... Specifying variables by string would require hacky implementation.

daattali commented 6 years ago

OK that's fine, colour is the more common way to map.

crew102 commented 6 years ago

This is ready for review. Not sure why git doesn't think that 7f9159cf64a25c0bd42d533e7aff8f3025cc34dc is the tip of this branch in daattali/ggExtra but it does for crew102/ggExtra. 7f9159cf64a25c0bd42d533e7aff8f3025cc34dc is indeed the tip (or at least I intended it to be).

daattali commented 6 years ago

Awesome! 3 small-ish comments:

  1. The Rd file still has the old version of the function where the parameter is a list
  2. Opinion on simplifying param name from "marginGroupColour" to "groupColour"?
  3. When the colour mapping in the scatterplot is a continuous rather than a discrete variable, the result is very awkward and unusable when using grouped marginal plots. What do you think of adding a check to see if the grouping variable is continuous, and if it is then error out or give a warning message? Example:

    p <- ggplot(mtcars) + geom_point(aes(x = wt, y = mpg, colour = hp))
    ggMarginal(p, marginGroupFill = TRUE)

    image

crew102 commented 6 years ago
  1. Yeah, was waiting on finalization of argument names/api before documenting. I'll add docs and push again.
  2. Sure, I like that better.
  3. Yes, colour has to be a factor. I'll add an assertion for this.
daattali commented 6 years ago

Assertion is good. And if it fails, then there should be a clear error message, because it may be confusing to someone why aes(col = gear) appears to result in the same scatterplot (except for the legend).

crew102 commented 6 years ago

Does this error message work for you?: Error: Colour must be mapped to a factor or character variable (not a numeric variable) in your scatter plot if you set groupColour = TRUE or groupFill = TRUE

daattali commented 6 years ago

Yep that's good. Would it then not work if the options are strings rather than factor levels? Maybe if the variable is character data then also allow it


Dean Attali President & CEO AttaliTech Ltd http://AttaliTech.com http://attalitech.com

On 16 January 2018 at 17:31, Chris Baker notifications@github.com wrote:

Does this error message work for you?: Error: Colour must be mapped to a factor variable (not a numeric variable) in your scatter plot if you set groupColour = TRUE or groupFill = TRUE

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/daattali/ggExtra/pull/66#issuecomment-358129906, or mute the thread https://github.com/notifications/unsubscribe-auth/AA6IFENVo3K7XRgdiYShDD3uPRiRxQSqks5tLSMogaJpZM4PlFVw .

crew102 commented 6 years ago

actually edited my comment so it says "factor or character variable" instead of "factor variable" for that reason (i.e., that it can be char or factor var)

crew102 commented 6 years ago

I decided to not rebase, and instead just add a few extra commits. This is ready for review

daattali commented 6 years ago

@crew102 I tested it and couldn't break it - works great :)

One last thing - it looks like the margins are off or some other visual issue is going on, at least for me. Whenever the marginal plot is close to 0, it disappears. Here's how the plot from the example looks to me:

p <- ggplot2::ggplot(mtcars, ggplot2::aes(x = wt, y = drat, colour = factor(vs))) +
    ggplot2::geom_point()
ggMarginal(p, groupColour = TRUE)

image

crew102 commented 6 years ago

Yeah, that kinda bothered me too. The reason why the line seems to disappear is that it's getting covered by a horizontal white line that gets added to all marginal density plots at y = 0...This line covers the black line that occurs at the y= 0 for density plots (vertical white lines are also added at the x lims for the same reason). In other words, the white lines cover the black lines that I've highlighted with red boxes below. rplot

As a reminder, we used to use geom_line for the marginal density plots, so covering this line was never an issue. Since we may need to fill the marginal density plots now, we have to use geom_density (at least when margin mapping is specified by the user).

I think the only thing we could do to minimize this issue would be to use geom_line when margin mapping isn't used and use geom_density when it is. I think I prefer having a single approach, though, so unless you feel strongly about it I'd like to keep it as is. There also may be a way to drop the unwanted lines by trying to find the relevant line grobs inside the ggplot grob and then deleting them from there, but I'm not sure.

daattali commented 6 years ago

Ah yes I forgot about that change. I actually did use geom_density initially, and moved to gem_line for this exact reason! Would using geom_line(..., stat="density") work?

crew102 commented 6 years ago

We wouldn't be able to fill the density plots if we used geom_line, so I don't think so.

daattali commented 6 years ago

I also don't like the idea of using both geom_line() and geom_density() depending on whether there are marginal groups or not. But I don't like the density line falling off the plot even more. So I would much prefer to use geom_line() when possible. It would be awesome if RStudio allowed removing that border....

daattali commented 6 years ago

Twitter provided a possible solution (ugly code, but may work, I tried a simple case it worked) https://twitter.com/Sbudation15/status/956783850671263744

ggplot(mtcars,aes(mpg)) +
  geom_density(colour="NA", fill='blue') + 
  geom_line(stat="density", colour="red")
daattali commented 6 years ago

Thomas (who worked on ggplot with Hadley) also said to use that technique

crew102 commented 6 years ago

Oh cool, didn't know you could do that. I'll try integrating it.

daattali commented 6 years ago

Even @wch said that overlaying two geoms is the way to go https://twitter.com/winston_chang/status/957057715750166528

crew102 commented 6 years ago

I incorporated the new approach for marginal density plots. There's a strange issue going on for me - the "color" for marginal density plots (i.e., the outline of the density plot - the one that that get produced by geom_line) is not showing up for the y marginal density plots in the RStudio plot viewer pane. For example,

source("tests/testthat/helper-funs.R")
ggMarginal(
      p = margMapP(), groupColour = TRUE, fill = "grey"
    )

Results in this:

x

Notice how the y marginal density plot is not colored in the RStudio plot pane (on the right), but it is colored whenever you "zoom" into the graphics device (on the left). This issue doesn't happen for the other marginal plot types (e.g., histograms).

Any idea why this would be the case?

FYI this branch failed on travis b/c i haven't updated the expected test figs yet.

daattali commented 6 years ago

That is a very strange issue indeed. It looks fine to me. I'm on Windows with latest rstudio 1.1.414 -- perhaps you're on an older rstudio version?

I just remembered one more thing that would need updating except for the readme: the shiny app (runExample())! It can happen after this feature gets merged

crew102 commented 6 years ago

That is a very strange issue indeed. It looks fine to me. I'm on Windows with latest rstudio 1.1.414 -- perhaps you're on an older rstudio version?

I updated my RStudio and the issue is still there. I just tried on RStudio server and the issue isn't there. I'd like to try on my mac at home to confirm that the issue doesn't occur there as well before merging. If it doesn't happen there, I'll push the updated test figs and then everything should be all set.

I just remembered one more thing that would need updating except for the readme: the shiny app (runExample())! It can happen after this feature gets merged

I can incorporate the feature in the shiny app. Do you think it also needs to go in the readme? I prefer shorter readmes with just the basics, but it's fine by me if we also incorp it there as well.

daattali commented 6 years ago

I'd add one example of it it to the readme, it's a pretty major feature! :)


Dean Attali President & CEO AttaliTech Ltd http://AttaliTech.com http://attalitech.com

On 5 February 2018 at 07:14, Chris Baker notifications@github.com wrote:

That is a very strange issue indeed. It looks fine to me. I'm on Windows with latest rstudio 1.1.414 -- perhaps you're on an older rstudio version?

I updated my RStudio and the issue is still there. I just tried on RStudio server and the issue isn't there. I'd like to try on my mac at home to confirm that the issue doesn't occur there as well before merging. If it doesn't happen there, I'll push the updated test figs and then everything should be all set.

I just remembered one more thing that would need updating except for the readme: the shiny app (runExample())! It can happen after this feature gets merged

I can incorporate the feature in the shiny app. Do you think it also needs to go in the readme? I prefer shorter readmes with just the basics, but it's fine by me if we also incorp it there as well.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/daattali/ggExtra/pull/66#issuecomment-363113968, or mute the thread https://github.com/notifications/unsubscribe-auth/AA6IFDY0NBpm06YTGW-klYgjZwSF4ziJks5tRxq5gaJpZM4PlFVw .

crew102 commented 6 years ago

OK so it looks like the issue only occurs on my windows machine. I've updated the expected figs, so this PR should be set to go.

Regarding updating the example shiny app, it may be a little awkward b/c the faithful and rock data frames don't have any vars that would be good to map to color in the scatterplot, which is what we would need in order to show the mapping in the marginals.

daattali commented 6 years ago

No worries, I'll update the readme later and just change it to iris

On Feb 5, 2018 19:19, "Chris Baker" notifications@github.com wrote:

OK so it looks like the issue only occurs on my windows machine. I've updated the expected figs, so this PR should be set to go.

Regarding updating the example shiny app, it may be a little awkward b/c the faithful and rock data frames don't have any vars that would be good to map to color in the scatterplot, which is what we would need in order to show the mapping in the marginals.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/daattali/ggExtra/pull/66#issuecomment-363266519, or mute the thread https://github.com/notifications/unsubscribe-auth/AA6IFKt0DcoyFLg4r2-RTz4weZCO0F5Yks5tR5qhgaJpZM4PlFVw .

daattali commented 6 years ago

Sorry to give bad news, but I just installed the latest version of the PR and I'm not seeing any marginal plots along the y axis for groupColour.

ggMarginal(p, groupColour = TRUE)

image

If I change it to groupFill then the fill does show up properly. But also using groupFill and groupColour together only shows the full but not the colour outline. Can you verify it's fine for you in RStudio?

crew102 commented 6 years ago

yeah so this is probably the same issue i was mentioning before...in the example i gave i specified fill = grey (which allowed you to see that the density plot exists on right side, but the color wasn't being added). what's weird is that it was working before for you, right? or maybe you just hadn't pulled the most recent version of the branch?

this is a problem that occurs only on windows. on mac/linux it doesn't happen. i have no idea why it's happening on windows.

daattali commented 6 years ago

I've just tried the different commits from the past month. It is definitely https://github.com/crew102/ggExtra/commit/0c69021d3c5ebe7718ccf70c7c435fec561dd87a that causes this. You might have known that already, but now it's verified. Somewhere in those dozen lines that have been changed lies the culprit...

crew102 commented 6 years ago

I fiddled around a bunch to try to figure out what's going on here and I'm stumped.

What's weird is that if you put a browser statement at line 154 in ggMarginal.R, you'll see that at that point in the execution you can't see the top marginal plot (i.e., printing top will result in no output in the RStudio plots pane), but you can print the the right marginal plot (right). This is weird b/c for some reason the right marginal plot is the one that ends up not showing up in the final plot.

crew102 commented 6 years ago

Changing the sizing of the plot pane can help (i.e., the lines may show up if you make the plot pane very large).

https://support.rstudio.com/hc/en-us/articles/200488548-Problem-with-Plots-or-Graphics-Device

daattali commented 6 years ago

You're right, resizing does sometimes fix it. Strangely, sometimes making the window wider makes the lines appear, and even wider makes them disappear again, but wider again makes them re-appear again.

Very buggy behaviour from the IDE, so it's likely not the fault of the code here :) Have you been able to isolate this behaviour in a smaller reproducible example so that rstudio can try to fix it?

crew102 commented 6 years ago

I did try to create a minimal reproducible example but I'm afraid it's not so minimal...I can't figure out a way to reproduce the behavior without including most of the code in ggmarginal.

Just to clarify, the issue occurs when groupColour = TRUE and type = "density" (I think both of these things have to occur, though I haven't throughly investigated). I suggest we throw a warning when these are both true and be done with it. Otherwise we'd have to go back to using white cover lines or wait for some external support (perhaps a tweet is in order? Though again it's hard to describe the problem without copying over most of ggmarginal).

daattali commented 6 years ago

I would be happy to tweet to try to get some help to solve it. Were you able to get any sort of reproducible example that is even slightly more isolated than ggmarginal, or should I just link to this PR?

crew102 commented 6 years ago

I did the best I could to isolate one point in ggMarginal where you can see the issue occur. If you source gr-device-mystery.R in my gr-device-mystery branch (https://github.com/crew102/ggExtra/commit/978a17a6a6d3172dc613142b8dc186ea32612286), you'll see an example where the density plots go from having colors in the plots pane to not having colors, for no apparent reason (only happens on Windows).

asdf

daattali commented 6 years ago

Thanks!

I've tried making this as minimal as possible, and here's what I came up with:

bug1 <- function(p) {
  pb <- ggplot2::ggplot_build(p)
  data <- subset(pb$data[[1]], select = c("x", "colour", "group"))
  colours <- setNames(unique(data$colour), unique(data$colour))
  noGeomPlot <- ggplot2::ggplot(
    data = data, mapping = ggplot2::aes(x = x, colour = colour, group = group)) +
    ggplot2::scale_colour_manual(values = colours)

  geomFun <- function(...) ggplot2::geom_density(colour = "NA", ...)
  density_parms <- list("fill"="grey", "alpha"=0.5)
  layer1 <- do.call(geomFun, density_parms)
  line_parms <- density_parms[names(density_parms) != "fill"]
  line_parms$stat <- "density"
  layer2 <- do.call(ggplot2::geom_line, line_parms)
  plot <- noGeomPlot + layer1 + layer2
  plot
}

bug2 <- function(p) {
  p + ggplot2::theme(
    axis.title.x = ggplot2::element_blank(),
    axis.text.x = ggplot2::element_blank(),
    plot.margin = grid::unit(c(0, 0, 0, 0), "null"),
    panel.background = ggplot2::element_blank(),
    axis.ticks.length = grid::unit(0, "null")
  )
}

p <-
  ggplot2::ggplot(mtcars,
                  ggplot2::aes(x = wt, y = drat, colour = factor(vs))) +
  ggplot2::geom_point() +
  ggplot2::scale_colour_manual(values = c("green", "blue"))

################

p1 <- bug1(p)
print(p1)
# Note how density plots are colored (green and blue). But in the legend, there
# is no line colour

p2 <- bug2(p1)
print(p2)
# Now colors are gone in plots pane, but exist when you "zoom in"

This is about 20 lines of absolutely minimal code without anything unnecessary (I think) that reproduces both problems

daattali commented 6 years ago

I found the problem!!! :tada:

Supplying alpha to geom_line() seems to break it. Definitely a ggplot2 bug. Here's the reprex:

ggplot(mtcars, aes(wt, colour = factor(vs))) + geom_line(stat="density", alpha = 0.9)

This has been one hell of a bug :/