Transform x,y coordinate space in ggplot - r

I know that you can transform the coordinates of a plot using coord_trans(), and you can even perform coordinate transformations along both axes (e.g. coord_trans(x = "log10", y = "log10")), but is there a way to perform a coordinate transformation that depends on the values of both axes, like a shear?
I know that I can perform the linear transformation before I pass my data to ggplot using something like ggforce::linear_trans() like this example:
trans <- linear_trans(shear(1, 0))
square <- data.frame(x = c(0, 0, 1, 1), y = c(0, 1, 1, 0))
square2 <- trans$transform(square$x, square$y)
ggplot(square2, aes(x, y)) +
geom_polygon(colour = 'black')
However, I'm hoping that there would be a way to write a custom coordinate system such that the data doesn't need to be transformed beforehand, e.g.:
square <- data.frame(x = c(0, 0, 1, 1), y = c(0, 1, 1, 0))
ggplot(square, aes(x, y)) +
geom_polygon(colour = 'black') +
coord_shear(x=1)

I implemented a custom coord that does this. It takes a transformer like that produced by ggforce::linear_trans and applies it to a ggplot. Check it out in my deeptime package here.

Related

Time-varying width of geom_segment in ggplot2

I would like to plot a rectangle whose width increases as the x-axis on a plot increases. Geom_segment is a great way to plot lines but you cannot map size within aes(). You can only select one size for the entire segment:
geom_segment(aes(x=5,xend=10,y=10,yend=10),size=10)
This doesn't work, the size doesn't vary with the value of x_axis_variable:
geom_segment(aes(x=5,xend=10,y=10,yend=10,size=x_axis_variable))
where x_axis_variable is whatever continuous variable you have plotted on the x-axis.
Is there a workaround, or some other option, to plot a single line whose size varies along the X or Y axes?
I'm happy to post some example data, but I'm actually not sure how helpful it would be for this question because it's not dependent upon data structure. I think it's just an artifact of geom_segment and hopefully there's another option. Thanks!
Edit with sort of the expected output:
Except that I'd like the line to increase gradually over the x-axis, not discretely as in the example.
Can you just use geom_line()?
library(tidyverse)
library(ggplot2)
d <- tibble(x = 1:20, y=5)
ggplot(d, aes(x=x, y=y, size=I(x), color=x)) +
geom_line()
Geom_segment is a great way to plot lines but you cannot map size
within aes().
Is this premise true? Check out my artistic chart:
ggplot(mtcars) +
geom_segment(aes(wt, mpg, xend = dplyr::lead(wt),
yend = dplyr::lead(mpg), size = gear))
Or this:
ggplot(data = data.frame(x = 1:5),
aes(x = x, xend = x + 1,
y = 0, yend = 0, size = x)) +
geom_segment()
geom_segment draws one segment with one size for each element of data you map. If you want the single segment to vary along its length, you might use ggforce::geom_link, like here, where it interpolates the size by making the segment into many pieces.
ggplot() +
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 0)) +
ggforce::geom_link(aes(x = 0, xend = 1, y = 0.5, yend = 0.5, size = after_stat(index)^2)) +
scale_size(range = c(0,10))
For a rectangle you might do something like:
ggplot() +
ggforce::geom_link2(aes(x = c(0, 0, 1, 1, 0),
xend = c(0, 1, 1, 0, 0),
y = c(0,1,1,0, 0),
yend = c(1,1,0,0, 1),
size = c(1,1,2,2, 1)), lineend = "round")

How to add to ggplot2 plot inside of for loop

I'm trying to plot multiple circles of different sizes on a plot using ggplot2's geom_point inside of a for loop. Every time I run it though, it plots all the circles, but all in the location of the last circle instead of in their respective locations as given by the data frame. Below is an example of the code I am running. I'm wondering how I would fix this or if there's a better way to get at what I'm trying to do here.
data <- data.frame("x" = c(0, 500, 1000, 1500, 2000),
"y" = c(1500, 500, 2000, 0, 1000),
"size" = c(3, 5, 1.5, 4.2, 2.6)
)
g <- ggplot(data = data, aes(x = x, y = y)) + xlim(0,2000) + ylim(0,2000)
for(i in 1:5) {
g <- g + geom_point(aes(x=data$x[i],y=data$y[i]), size = data$size[i], pch = 1)
}
print(g)
It's pretty rare to need a for-loop for a plot -- ggplot2 will take the whole dataframe and process it all without you needing to manage each row.
ggplot(data = data, aes(x = x, y = y, size = size)) +
geom_point(pch = 1)

how to make a vertical line segment in plot?

I have a plot(x, y) and I want to add a vertical line at x = 2 ONLY from y = 1 to 4. I want to use the lines() function but I'm having trouble limiting the y-range.
What's an easy way to do this?
Here's a simple example of using plot and lines. To draw a line from (2, 1) to (2, 4), you have to provide the x coordinates and y coordinates as (2, 2) and (1, 4):
plot(1:5)
lines(c(2, 2), c(1, 4))
ggplot2 offers a very simple solution, too!
library(ggplot2)
set.seed(1)
# Create some dummy data
data.frame(X = rpois(n = 10, lambda = 3),
Y = rpois(n = 10, lambda = 2)) %>%
# Pipe to ggplot
ggplot(aes(X, Y)) +
geom_point() +
geom_segment(aes(x = 1, xend = 1, y = 1, yend = 4), color = "red")
Within the aesthetics call to geom_segment() you can select the start and end points for your x and y parameters. You can then easily add multiple segments by simply adding + geom_segment(aes(...)) to the end of the code above.
For completeness, there is also a base graphics function in R that will do this: segments(x0,y0,x1,y1):
plot(1:5)
segments(2,1,2,4)

Is it possible to insert a line of no discrimination in ROC plot using ggroc?

I have created a ROC plot with multiple ROC-curves using ggroc based on pROC. How can I insert a line of no discrimination?
I would like to have a line of no discrimination from 0,0 to 1,1 in my plot, so that I can better visually evaluate my ROC-curves.
I have tried using the plot() function on my ggplot object, and I have tried using + geom_abline(), and the lines() function without any luck.
library(pROC)
#Creating curves and labeling)
ROC_curves <- ggroc(list(log=ROC_log, tree=ROC_tree, xgbt=ROC_xgbt), legacy.axes=TRUE)
ROC_curves2 <- ROC_curves + xlab("FPR") + ylab("TPR")
#but this part doesn't Work:
+ qplot(1,1) + geom_abline(intercept=0, slope=1)
I have also tried doing:
plot(ROC_curves2, identity=TRUE)
I would like a line of no discrimination going from 0,0 to 1,1 in my plot.
When adding qplot(1,1) + geom_abline(), I get "Error: Don't know how to add o to a plot".
When using plot() a plot is returned, but still with no line.
The ROC_curves already returns a ggplot plot. Adding a new plot to it with qplot is not possible nor necessary, just add geom_abline directly:
ROC_curves + xlab("FPR") + ylab("TPR") +
geom_abline(intercept = 0, slope = 1,
color = "darkgrey", linetype = "dashed")
The abline extends beyond the limits of the ROC curve. To avoid that you can use geom_segment instead:
ROC_curves + xlab("FPR") + ylab("TPR") +
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1),
color="darkgrey", linetype="dashed")
Also note that if you weren't using legacy.axes=TRUE you would need to have intercept = 1 so that the line crosses the 0 line on the top right.
... + geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1)) # legacy.axes = TRUE
... + geom_segment(aes(x = 1, xend = 0, y = 0, yend = 1)) # legacy.axes = FALSE
#Calimo's solution didn't work for me but I think that is due to the size of my dataset so the graph won't render. Found a gitlab issue (https://github.com/tidyverse/ggplot2/issues/4190) about how annotate is much faster than geom_segment. I'm using the following:
+ annotate("segment",x = 1, xend = 0, y = 0, yend = 1, color="red", linetype="dashed")

Multiple Layers in ggplot2

I want to overlay a plot of an empirical cdf with a cdf of a normal distribution. I can only get the code to work without using ggplot.
rnd_nv1 <- rnorm(1000, 1.5, 0.5)
plot(ecdf(rnd_nv1))
lines(seq(0, 3, by=.1), pnorm(seq(0, 3, by=.1), 1.5, 0.5), col=2)
For ggplot to work I would need a single data frame, for example joining rnd_vn1 and pnorm(seq(0, 3, by=.1), 1.5, 0.5), col=2). This is a problem, because the function rnorm gives me just the function values without values on the domain. I don't even know how rnorm creates these, if I view the table I just see function values. But then again, magically, the plot of rnd_nv1 works.
The following plots the two lines but they overlap, since they are almost equal.
set.seed(1856)
x <- seq(0, 3, by = 0.1)
rnd_nv1 <- rnorm(1000, 1.5, 0.5)
dat <- data.frame(x = x, ecdf = ecdf(rnd_nv1)(x), norm = pnorm(x, 1.5, 0.5))
library(ggplot2)
long <- reshape2::melt(dat, id.vars = "x")
ggplot(long, aes(x = x, y = value, colour = variable)) +
geom_line()

Resources