How to Jitter Two Ggplot Geoms in the Same Way

Is it possible to jitter two ggplot geoms in the same way?

This is a weakness in the current ggplot2 syntax - there's no way to work around it except to add the jitter yourself.

Or you could do something like this:

ggplot(baseball, aes(round(year,-1) + as.numeric(factor(lg)), sb, color = factor(lg))) +
stat_summary(fun.data="mean_cl_normal") +
stat_summary(fun.y=mean,geom="line") +
coord_cartesian(ylim=c(0,40))

Apply jitter uniformly across geoms in ggplot2

Using position_jitter function, you can add a seed value to get reproducible jitter effect:

library(ggplot2)

ggplot(pdat, aes(x = x, y = y, ymin = ymin, ymax = ymax, color = colour))+
geom_point(position = position_jitter(seed = 123, width =0.2))+
geom_linerange(position = position_jitter(seed = 123, width = 0.2))

Sample Image

Does it answer your question ?

How to jitter both geom_line and geom_point by the same magnitude?

Another option for horizontal only would be to specify position_dodge and pass this to the position argument for each geom.

pd <- position_dodge(0.4)

ggplot(data = df, aes(x = dimension, y = value,
shape = Time, linetype = Time, group = Time)) +
geom_line(position = pd) +
geom_point(position = pd) +
xlab("Dimension") + ylab("Value")

Sample Image

Highlighting some points with constant jitter across plots (ggplot2)

As compared to your solution of layering two jitters, the fill approach was in the right direction. However, fill works only for shapes 21-25, so you were not able to see the desired result.

Graph with all points:

myseed=101
set.seed(myseed)
p <- ggplot(dr, aes(x=X,y=Y,colour=Y)) +
theme_bw() +
geom_jitter(alpha=0.7,width=0.5, size = 3) +
scale_colour_gradient("Y", low="#5edcff", high="#035280") +
stat_summary(fun.y = "mean", fun.ymin = "mean", fun.ymax= "mean", size=0.3,width=0.33, geom = "crossbar")
plot(p)

Sample Image

Graph with highlighted points:

Note that I supplied aesthetics to stat_summary again, otherwise it would generate another summary for the fill layer.

myseed=101
set.seed(myseed)
p <- ggplot(dr, aes(x=X,y=Y,colour=Y, fill = factor(highlight))) +
theme_bw() +
geom_jitter(width=0.5, shape = 21, size = 3) +
scale_colour_gradient("Y", low="#5edcff", high="#035280") +
scale_fill_manual(values=c("red"), guide = FALSE) +
stat_summary(aes(x=X,y=Y,colour=Y), inherit.aes = FALSE,
fun.y = "mean", fun.ymin = "mean", fun.ymax= "mean", size=0.3,width=0.33, geom = "crossbar")
plot(p)

Sample Image

I still think a cleaner solution would be to manually code the colors, but I did not attempt it. Maybe someone will supply that solution.

Subdividing jitter points in ggplot

Found a solution using:
geom_point(position=position_jitterdodge())

This seems to jitter and dodge to separate the points.

Jitter geom_line and geom_point

You can pass the argument seed into position_jitter in order to make the same jitter effect between geom_point and geom_line:

ggplot(data = test, aes(
x = time_point, y = Q10, color = storage_temp
)) +
geom_point(
data = test,
aes(time_point, Q10, group = storage_temp),
alpha = 0.25,
color = 'black',
position = position_jitter(width = 0.25, seed = 123)
) +
geom_line(
data = test,
aes(group = individual_code, linetype = storage_temp),
color = 'black',
alpha = 0.25,
position = position_jitter(width = 0.25, seed = 123)
)

Sample Image

Does it answer your question ?

selective jitter of geom_points

We can use duplicated or any similar function to detect the overlap, then we can use R indexing with jitter to apply jitter selectively.

I wrote it as a function:

selective_jitter <- function(x, # x = x co-ordinate
y, # y = y co-ordinate
g # g = group
){
x <- as.numeric(x)
y <- as.numeric(y)
a <- cbind(x, y)
a[duplicated(a)] <- jitter(a[duplicated(a)], amount = .15) # amount could be made a parameter

final <- cbind(a, g)
return(final)
}

data <- as.data.frame(selective_jitter(data$x, data$y, data$type))

ggplot() + geom_point(data = data, aes(x=x,y=y, color = g, fill = type), size = 2, shape = 25)

Sample Image

There are a lot of ways to write this differently or to tweak it. For instance, I think a very nice tweak would be to add an optional argument for the amount option of jitter().

Another potential improvement would be to use a caliper to look for (near-) duplicates as well as the exact duplicates (whereas duplicated will just find exact dupes).

Final note - sometimes when I do this I like to use semi-transparent colors rather than jitter. This variation works well only if the number of series (type) is small, so that you can do things like have 1 series in yellow, 1 in blue, and then their overlap would be green (there are existing solutions on Stack Overflow) that demonstrate that if you're interested.

How is jitter determined in ggplot?

If we look at the source we first find this:

PositionJitter <- proto(Position, {
objname <- "jitter"

adjust <- function(., data) {
if (empty(data)) return(data.frame())
check_required_aesthetics(c("x", "y"), names(data), "position_jitter")

if (is.null(.$width)) .$width <- resolution(data$x, zero = FALSE) * 0.4
if (is.null(.$height)) .$height <- resolution(data$y, zero = FALSE) * 0.4

trans_x <- NULL
trans_y <- NULL
if(.$width > 0) {
trans_x <- function(x) jitter(x, amount = .$width)
}
if(.$height > 0) {
trans_y <- function(x) jitter(x, amount = .$height)
}

transform_position(data, trans_x, trans_y)
}

})

And wouldn't you know it, resolution is an exported function (or you could just search the sources for it landing you here):

function (x, zero = TRUE) 
{
if (is.integer(x) || zero_range(range(x, na.rm = TRUE)))
return(1)
x <- unique(as.numeric(x))
if (zero) {
x <- unique(c(0, x))
}
min(diff(sort(x)))
}

So...there you go!

"resolution" in this context then roughly means "the smallest distance between any two elements in a vector".

This value (40% of the resolution) is then passed on as the factor argument to jitter, which has it's own little song and dance:

The result, say r, is r <- x + runif(n, -a, a) where n <- length(x)
and a is the amount argument (if specified).

Let z <- max(x) - min(x) (assuming the usual case). The amount a to be
added is either provided as positive argument amount or otherwise
computed from z, as follows:

If amount == 0, we set a <- factor * z/50 (same as S).

If amount is NULL (default), we set a <- factor * d/5 where d is the
smallest difference between adjacent unique (apart from fuzz) x
values.



Related Topics



Leave a reply



Submit