tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.54k stars 2.03k forks source link

Change aesthetics after the fact ? (possibly more a question than an issue) #2771

Closed EmmanuelCharpentier closed 6 years ago

EmmanuelCharpentier commented 6 years ago

A lot of R packages now use ggplot2 for the display of their results, thus avoiding their users a lot of work. However, this gives sometimes results inadapted to some category of problems (or users).

Being (quite partially) color-blind, I have trouble using a lot of packages using colour as their main (sole) aesthetic for categorical variables. Latest case in point : plot(marginal_effects(<some brms GAM model>), points=TRUE) displays :

The latter is not fine at all : those points are too small to allow me to detect their colour differences ; furthermore, most of them are overlaid on a colored surface representing the confidence bands of the splines. It becomes impossible to tell if a given point is or is not in the confidence band of its group.

Using a shape aesthetic to represent the group to which each point belongs to would have make this a piece of cake... I was hoping that would be possible to write something allowing to change/augment the aesthetics of a given plot, along the line of

plot(marginal_effects(<some brms GAM model>), points=TRUE) + geom_point(shape=<group variable>)

but perusing the docs didn't show anything obvious, and some semi-blind attempts failed miserably.

So the question is : is this kind of post-hoc handling is :

Cordially yours !

batpigandme commented 6 years ago

Hi Emmanuel,

I'm guessing the answer is largely "it depends." If there's a specific example you're thinking of, I'd be happy to try to run it, but based on the information you gave, I made an example using the plot method from ggeffects (vignette here).

Using the method you described above, I was able to attempt the sort of post-hoc handling by specifying the data mapping used in the original plot, and adding the aes() of shape = group. However, that change seems to be applied to the smooth, as opposed to the raw data points.

# source: https://cran.r-project.org/web/packages/ggeffects/vignettes/plotmethod.html
library(ggeffects)
library(sjmisc)
library(ggplot2)
data(efc)
efc$c172code <- to_label(efc$c172code)
fit <- lm(barthtot ~ c12hour + neg_c_7 + c161sex + c172code, data = efc)

# plot raw data
dat <- ggpredict(fit, terms = c("c12hour", "c172code"))
#> Following variables had many unique values and were prettified: c12hour. Use `pretty = FALSE` to get smoother plots with all values, however, at the cost of increased memory usage.
plot(dat, rawdata = TRUE) +
  geom_point(data = dat, aes(shape = group))

Created on 2018-07-23 by the reprex package (v0.2.0.9000).

This even happens if I explicitly map the x and y aesthetics:

plot(dat, rawdata = TRUE) +
  geom_point(data = dat, aes(x = x, y = predicted, shape = group))

The good news is that I'm by no means the most skilled of ggplot2 practitioners, so it's possible that there's something I'm missing.

EmmanuelCharpentier commented 6 years ago

Dear Mara,

Thank you very much for this prompt answer.

Using the method you described above, I was able to attempt the sort of post-hoc handling by specifying the data mapping used in the original plot, and adding the aes() of shape = group. However, that change seems to be applied to the smooth, as opposed to the raw data points.

My point is to (try to) do that without the original source code of the plot (generated by a quite complex package), but only the data recorded in the plot. Your example gave me ideas, but so far, I'm unable to access the "right" part of the plot. My attempts usually end up returning NULL...

So my question remains. But I'm afraid that the third term of the alternative is more probable than the two other ones...

hadley commented 6 years ago

I think this is something that you really need to request of the original function author; there is currently no API for post-hoc editing of ggplot2 graphics.

batpigandme commented 6 years ago

My point is to (try to) do that without the original source code of the plot (generated by a quite complex package), but only the data recorded in the plot.

Do you mean, like, from a plot, but without any other information? The only thing I can think of that does something similar is Adobe Illustrator, where you can select Same Appearance, but I have no idea how to transform the shapes from there

image

clauswilke commented 6 years ago

You can use layer_data() to extract the data from a plot and replot. You're losing the information about labels and legend keys in the process, but those can be recovered manually if needed.

library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width, colour = Species)) +
  geom_point()

p


ggplot(layer_data(p), aes(x, y, colour = colour, shape = colour)) +
  geom_point() +
  scale_colour_identity(guide = "legend")

Created on 2018-07-23 by the reprex package (v0.2.0).

hadley commented 6 years ago

Even in that case, you'd be better of pushing on the author of the original code to provide data and plot separately. Only providing the plot is not inline with tidy principles.

lock[bot] commented 5 years ago

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/