geom_line for a parametric function - r

Here is an example for visualizing Bezier curve:
library(ggplot2)
t = seq(0, 1, 0.001)
x0 = 4
y0 = 1
x1 = 28
y1 = 48
x2 = 50
y2 = 42
x3 = 40
y3 = 5
x = x0 * (1 - t)^3 + 3 * x1 * t * (1 - t)^2 + 3 * x2 * t^2 * (1 - t) + x3 * t^3
y = y0 * (1 - t)^3 + 3 * y1 * t * (1 - t)^2 + 3 * y2 * t^2 * (1 - t) + y3 * t^3
data = data.frame(x, y)
data1 = data.frame(x = c(x0, x2), xend = c(x1, x3), y = c(y0, y2), yend = c(y1, y3))
data2 = data.frame(x = c(x0, x1, x2, x3), y = c(y0, y1, y2, y3))
mplot = ggplot(data, aes(x, y)) + geom_line() + geom_segment(data = data1, aes(x = x, y = y, xend = xend, yend = yend)) + geom_point(data = data2, aes(x, y))
mplot
Result:
The right part of the curve has been rendered as an area. I guess this is because the y-values are not unique for certain x-values. How to solve this?

Instead of using geom_line() you may use geom_path():
ggplot(data, aes(x, y)) +
geom_path() +
geom_segment(data = data1, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_point(data = data2, aes(x, y))
... or even geom_point() would do the trick, but I guess you would have to play with point size to get what you want.

Related

How to add a legend in ggplot to my graph

Hi have some code to simulate a Gaussian process. Please can someone help me add a legend to my plots on the top right corner. I want to state the different parameter values for each of the line styles/colours, e.g. l=1, l=5, l=10. Thanks.
# simulate a gaussian process
simGP = function(K){
n = nrow(K)
U = chol(K) # cholesky decomposition
z = rnorm(n)
c(t(U) %*% z)
}
# choose points to simulate the covariance.
x = seq(-1, 1, length.out = 500)
# Exponential kernel ------------------------------------------------------
kernel_exp = function(x, l = 1) {
d = as.matrix(dist(x))/l
K = exp(-d)
diag(K) = diag(K) + 1e-8
K
}
{y1 = simGP(kernel_exp(x,l=10))
y2 = simGP(kernel_exp(x,l=1))
y3 = simGP(kernel_exp(x,l=0.1))
data1 <- as.data.frame(x,y1)
data2 <- as.data.frame(x,y2)
data3 <- as.data.frame(x,y3)
df=data.frame(data1,data2,data3)
ggplot() +
geom_line(data=data1, aes(x=x, y=y1), color="green4", linetype = "twodash", size=0.5) +
geom_line(data=data2, aes(x=x, y=y2), color='red', linetype="longdash", size=0.5) +
geom_line(data=data3, aes(x=x, y=y3), color='blue') +
scale_color_manual(values = colors) +
theme_classic() +
labs(x='input, x',
y='output, f(x)')+
theme(axis.text=element_text(size=16),
axis.title=element_text(size=14))}
You can do it using a dataframe variable to group the linetype and colour.
If you want to specify color and linetype, use scale_color_discrete and scale_linetype_discrete
y1 = simGP(kernel_exp(x,l=10))
y2 = simGP(kernel_exp(x,l=1))
y3 = simGP(kernel_exp(x,l=0.1))
data1 <- data.frame(x, y = y1, value = "10")
data2 <- data.frame(x, y = y2, value = "1")
data3 <- data.frame(x, y = y3, value = "0.1")
df=rbind(data1,data2,data3)
ggplot(data = df, aes(x=x, y=y, color = value, linetype = value, group = value)) +
geom_line(size=0.5) +
theme_classic() +
labs(x='input, x',
y='output, f(x)')+
theme(axis.text=element_text(size=16),
axis.title=element_text(size=14))

ggplot2 legend: how to combine the linetype and shape

I am using ggplot to plot the following graph (one example attached). What I want to achieve is to have one legend to show linetype 4 & shape 1 combined as "group 1" and linetype 1 & shape 2 combined as "group 2". Also, the legend name will be something such as "example legend" (based on df1,df2: separate into group 1 and group 2 and each group has 3 lines)
I tried scale_shape_manual and scale_linetype_manual. However, I didn't find the right way. The code is listed as below (the graph has no legend which I want to add correctly)
Thanks.
y1 <- x + 0.01
y2 <- x + 10
df1 <- data.frame(x, y1)
df2 <- data.frame(x, y2)
graph_1 <- subset(df1, x >= 0 & x <= 5)
graph_2 <- subset(df1, x >= 6 & x <= 10)
graph_3 <- subset(df1, x >= 11 & x <= 15)
graph_4 <- subset(df2, x >= 0 & x <= 5)
graph_5 <- subset(df2, x >= 6 & x <= 10)
graph_6 <- subset(df2, x >= 11 & x <= 15)
win.graph(width = 13, height = 6, pointsize = 8)
ggplot() +
geom_point(aes(x, y1), data = graph_1, shape = 1) +
geom_smooth(aes(x, y1), data = graph_1, method = "loess", linetype = 4) +
geom_point(aes(x, y1), data = graph_2, shape = 1) +
geom_smooth(aes(x, y1), data = graph_2, method = "loess", linetype = 4) +
geom_point(aes(x, y1), data = graph_3, shape = 1) +
geom_smooth(aes(x, y1), data = graph_3, method = "loess", linetype = 4) +
geom_point(aes(x, y2), data = graph_4, shape = 2) +
geom_smooth(aes(x, y2), data = graph_4, method = "loess", linetype = 1) +
geom_point(aes(x, y2), data = graph_5, shape = 2) +
geom_smooth(aes(x, y2), data = graph_5, method = "loess", linetype = 1) +
geom_point(aes(x, y2), data = graph_6, shape = 2) +
geom_smooth(aes(x, y2), data = graph_6, method = "loess", linetype = 1)

Squared transform in coord ggplot2

I have data where I think that y^2 ~ x.
So, I want to plot y as a function of x with some transformed scaled for y.
N <- 100
ggplot(data_frame(x = runif(N), y = 20 * sqrt(x) + rnorm(N)), aes(x, y)) +
geom_point()
+ scale_y_square??
You need to make a new transformation with scales::trans_new and to use it with coord_trans:
N <- 100
ggplot(data_frame(x = runif(N), y = 20 * sqrt(x) + rnorm(N)), aes(x, y)) +
geom_point() +
coord_trans(y = scales::trans_new("square", function(x) x^2, "sqrt"))

Sapply instead of ggplot2 loop

Can someone please help me to create an sapply that will perform these plots. I understand the ggplot2 does not support loops.
code:
library(ggplot2)
meanX <- 5
meanY <- 5
x <- sin(1:10)
y <- 30:21
Res <-as.data.frame(cbind(x,y))
for (i in 1:nrow(Res))
{
ggplot(Res) + geom_point(aes(x = Res$x, y = Res$y)) +
geom_segment(aes(x = meanX, y = meanY, xend = Res$x[i], yend = Res$y[i]), Res )
}
In this case, you don't need any loop. You could just do
ggplot(data = Res) +
geom_point(aes(x = x, y = y)) +
geom_segment(aes(x = meanX, y = meanY, xend = x, yend = y))

include data from different dataframes, combining different geoms and with a legend which identifies the data source

I have three dataframes, containing data for the same variables (x and y, grouped by variable case) but each dataframe contains data from a different source (test, sim and model). The levels of case are identical for test and model, but they are different for sim. For each value of case, I want all xy curves from different sources but with the same case to have the same color. I need to have a legend which clearly identifies the data source, but I would also like to use different geoms for different data sources. This is what I've been able to do:
rm(list=ls())
gc()
graphics.off()
library(ggplot2)
# build the dataframes
nx <- 10
x1 <- seq(0, 1, len = nx)
x2 <- x1+ 0.1
x3 <- x2+ 0.1
x4 <- x3+ 0.1
x <- c(x1, x2, x3, x4)
y1 <- 1 - x1
y2 <- 1.1 * y1
y3 <- 1.1 * y2
y4 <- 1.1 * y3
y <- c(y1, y2, y3, y4)
z1 <- (y1 + y2)/2
z2 <- (y2 + y3)/2
z3 <- (y3 + y4)/2
z4 <- (y4 + 1.1 * y4)/2
z <- c(z1, z2, z3, z4)
w <- y*1.01
case_y <- c("I-26_1", "I00", "I20_5", "I40_9")
case_z <- c("I-23_6", "I00", "I22_4", "I42_3")
case_y <- rep(case_y, each = nx)
case_z <- rep(case_z, each = nx)
foo <- data.frame(x = x, y = z, case = case_z, type = "test")
bar <- data.frame(x = x, y = y, case = case_y, type = "sim")
mod <- data.frame(x = x, y = w, case = case_z, type = "model")
# different data frames have different factor levels: to avoid this,
# I bind all dataframes and I reorder the levels of case
foobar <- rbind(foo, bar, mod)
case_levels <- c("I-26_1", "I-23_6", "I00", "I20_5", "I22_4", "I40_9", "I42_3")
foobar$case <- factor(foobar$case, levels = case_levels)
# now I can plot the resulting dataframe
p <- ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1)
p
The problem here is that it's difficult to discern sim and model. In order to make a more readable plot, I switch to geom_point for the model data:
foobar <- rbind(foo, bar)
case_levels <- c("I-26_1", "I-23_6", "I00", "I20_5", "I22_4", "I40_9", "I42_3")
foobar$case <- factor(foobar$case, levels = case_levels)
mod$case <- factor(mod$case, levels = case_levels)
# now I can plot the resulting dataframe
p <- ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod)
However, now I don't have a model label in the legend. How can I make sure that the model curves are clearly labeled in the legend, but they are also easy to discern visually from the sim and test curves?
EDIT Procrastinatus Maximus suggests an edit to Pierre Lafortune's code which should eliminate the space between the model label and the type legend, but apparently it eliminates the space between model and the case legend instead:
ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod, aes(shape=type)) +
scale_shape_discrete(name="") +
guides(colour = guide_legend(override.aes = list(linetype=c(1),
shape=c(NA)))) +
theme(legend.margin = margin(0,0,0,0), legend.spacing = unit(0, 'lines'))
The result is
This will get you closer to your goal. I will look to see if we can close the gap between the two legends.
ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod, aes(shape=type)) +
scale_shape_discrete(name="") +
guides(colour = guide_legend(override.aes = list(linetype=c(1),
shape=c(NA))))
Edit
##ProcrastinatusMaximus
ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod, aes(shape = type)) +
guides(color = guide_legend(override.aes = list(linetype = c(1), shape = c(NA)), order = 1),
linetype = guide_legend(order = 2),
shape = guide_legend(title = NULL, order = 3))+
theme(legend.margin = margin(0,0,0,0), legend.spacing = unit(0, 'lines'))
Personally, I think all you need to do is change to order of the type, so that the solid line is in the middle. If you make the background white and the line colors a bit brighter, I think your figure is clear:
(p <- ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = rev(type)), size = 1) +
scale_color_manual(values = c("black","green","blue","purple","pink","red","brown"))+
theme_bw())

Resources