Use segments function to draw lines - r

I am trying to plot lines between my observed value and fitted value. But somehow I keep on getting error. I am using segments to do this. Below is my script:
mdl<-lm(yld ~ year,data=asm);summary(mdl)
plot(yld ~ year,data=asm,pch=16,xlab="Year",ylab=expression(paste("Raw rice yield (kg/ha)")))
abline(mdl)
x0 <- x1 <- mdl$mdl$year
y0 <- mdl$mdl$yld
y1 <- fitted(mdl)
segments(x0, y0, x1, y1, col="red", lwd=2)
Error in segments(x0, y0, x1, y1, col = "red", lwd = 2) :
invalid first argument
Could anyone tell me what am I doing wrong here? When I run x0 it shows NULL. Same for x1 and y1 (NULL). Is this the problem and how do I correct it
Thanks

Related

Is there a way to plot with 2 y values and one x

I want to make a plot which has two y values and I can't seem to be able to find any way to make it work I'd imagne the code would look something like this:
x1 = c(1,2,3,4,5)
y1 = c(10,13,15,17,11)
y2 = c(5,7,8,3,5)
plot(x1, y1, y2)
but I get the error:
Error in plot.xy(xy, type, ...) : invalid plot type
Use matplot as #jogo suggested
matplot(x1, cbind(y1, y2), pch=c(1, 2), col=c(2, 3), xlab="x", ylab="y", main="My plot")
legend("topleft", legend=c("y1", "y2"), pch=c(1, 2), col=c(2, 3))
You can also use ggplot:
library(ggplot)
ggplot() +
geom_point(aes(x = x1, y = y1)) +
geom_point(aes(x = x1, y = y2))
For completeness the base R solution looks like this:
> x1 = c(1,2,3,4,5)
> y1 = c(10,13,15,17,11)
> y2 = c(5,7,8,3,5)
> plot(x1, y1, type='l', ylim=c(0,20))
> lines(x1, y2, type='l', col='red')

Placing arrow heads to the middle of the lines in R

I have a plot where I draw arrows from points to points. I would like to put this arrow heads not to the end of the line, but to middle. Is there a simple way to do it other than placing extra arrows with half length of the according line?
My code is this:
plot(x, y, xlim=range(x), ylim=range(y), xlab="x", ylab="y", pch=16,
main="Filled Plane")
for(i in 1:20){
arrows(x[i], y[i], x[i+1], y[i+1], length = 0.25, angle = 30, col = i)
}
Make a custom function myArrow() and add one new argument cut to control the proportion of the arrows
myArrow <- function(x0, y0, x1, y1, cut = 1, ...){
x.new <- (1 - cut) * x0 + cut * x1
y.new <- (1 - cut) * y0 + cut * y1
# segments(x0, y0, x1, y1, ...)
arrows(x0, y0, x.new, y.new, ...)
}
Note1 : The computation of x.new and y.new in this custom function uses a simple mathematical concept, i.e. the Section Formula. The value of cut must be between 0 to 1.
Note2 : The use of this function is equivalent to that of the original functionarrows() other than that it has one more new argument cut.
Note3 : If you want complete lines behind the arrows, just remove the hash(#) in the function.
Plot and try different cut value. For example, I use cut = 0.7. (If you want the arrowheads to the middle, use cut = 0.5.)
# Toy Data
x <- seq(1, 5.5, by = 0.5)
y <- rep(c(1, 5), 5)
plot(x, y, pch = 16)
for(i in 1:9){
myArrow(x[i], y[i], x[i+1], y[i+1], cut = 0.7, col = i, lwd = 2)
}
Since you do not provide your x and y, I made up some data. There is no need for the loop. arrows will handle a vector of coordinates. One way is to draw a full-length arrow with no arrowhead and another that just goes halfway but has the arrowhead.
## Some bogus data
set.seed(123)
x = runif(4)
y = runif(4)
## Compute the midpoints
midx = diff(x)/2 + x[-length(x)]
midy = diff(y)/2 + y[-length(y)]
## Draw it
plot(x,y,xlim=range(x), ylim=range(y), xlab="x", ylab="y",
main="Filled Plane",pch=16)
arrows(x[-length(x)], y[-length(y)],x[-1],y[-1],
angle = 0, col = 1:3)
arrows(x[-length(x)], y[-length(y)],midx,midy,
length = 0.25, angle = 30, col = 1:3)

Using UTF-8 codes for use in intToUtf8() in R?

I'm trying to use UTF-8 code to put a symbol in some text in an R figure. If I wanted a black circle, I could use the code intToUtf8(9679). Where can I find a database that lists the values for other symbols? I want to find the code to create a red circle (i.e., pch=16, col="red"), but I can't find a list of what all of the unicode values are for specific symbols.
# example R code
x <- 1:10
y1 <- rnorm(10, x*2, 0.5)
y2 <- rnorm(10, x, 0.5)
plot(x, y1, xlab='x-value', ylab='', pch=16)
points(x, y2, pch=16, col='red')
mtext(paste0('value for y1 (', intToUtf8(9679), ') and y2 (', intToUtf8(9679), ')'), side=2, line=2)
# except that I want the second black circle in the axis label to be a red circle
Thank you for your help,
Mikey
Here is the solution I ended up using. It's not the most efficient, but it works:
x <- 1:10
y1 <- rnorm(10, x*2, 0.5)
y2 <- rnorm(10, x, 0.5)
plot(x, y1, xlab='x-value', ylab='', pch=16)
points(x, y2, pch=16, col='red')
mtext('value for y1 (\u25CF) and y2 ( )', side=2, line=2)
mtext(' \u25CF', side=2, line=2, col='red')
# alternatively, the following would also work in place of line 6
mtext(paste0('value for y1 (', intToUtf8(9679),' and y2 ( )'), side=2, line=2)
If you want to find more unicode character information for your specific symbol, you can look here.
Thank you lukeA for your help with this.

How to draw the curves in an energy diagram in R?

I wrote following R script:
#energy diagram
x <- c(0.1, 0.3, 0.5, 0.7, 0.9 ) #chosen randomly, reaction axis
y <- c(-5.057920, -5.057859, -5.057887,-5.057674, -5.057919 ) #energy of the educt, intermediate, transtition states and product
plot(x,y, type="p",
xlim=c(0,1),
ylim=c(-5.058,-5.0575),
xlab="reaction axis",
ylab=expression(paste(E[el] ," / ",10^6," ",kJ/mol)),
xaxt="n" #hide x-axis
)
#h- and v-lines, so i can draw curves by hand
abline(v=seq(0,1,0.1),h=seq(-5.0600,-5.0500,0.00005),col="black",lty=1,lwd=1)
abline(h=c(-5.057920, -5.057859, -5.057887,-5.057674), col="blue", lty=1,lwd=0.7)
Is it possible to draw a curve through the points that would look like a energy diagram. An example of an energy diagram is here:
A lot could be done to streamline / vectorize this code, but for a smallish diagram this works pretty well:
# get that data
x <- c(0.1, 0.3, 0.5, 0.7, 0.9 ) # reaction axis
y <- c(-5.057920, -5.057859, -5.057887,-5.057674, -5.057919 ) # energies
I'm going to make a little Bezier curve to connect each point to the next---this way we can make sure the smooth line passes through the data, not just close to it. I'll give each point a single 'control point' to define the slope. By using the same y-values for a point and it's control point, the slope at the point will be 0. I'll call the offset between the point and the control point delta. We'll start with one point-pair:
library(Hmisc)
delta = 0.15
bezx = c(0.1, 0.1 + delta, 0.3 - delta, 0.3)
bezy = rep(y[1:2], each = 2)
plot(bezx, bezy, type = 'b', col = "gray80")
lines(bezier(bezx, bezy), lwd = 2, col = "firebrick4")
Here I plotted the points and control points in gray, and the smooth line in red so we can see what's going on.
It looks promising, let's turn it into a function that we can apply to each pair of points:
bezf = function(x1, x2, y1, y2, delta = 0.15) {
bezier(x = c(x1, x1 + delta, x2 - delta, x2), y = c(y1, y1, y2, y2))
}
You can play with the delta parameter, I think 0.1 looks pretty good.
plot(x, y, xlab = "Reaction coordinate", ylab = "E", axes = F)
box(bty = "L")
axis(side = 2)
for(i in 1:(length(x) - 1)) {
lines(bezf(x1 = x[i], x2 = x[i + 1], y1 = y[i], y2 = y[i + 1], delta = 0.1))
}
You can of course tweak the plot, add labels, and ablines as in your original. (Use my for loop with the lines command to draw only the smoothed lines.) I left the points on to show that we are passing through them, not just getting close.
I prefer plotting in ggplot2, if you do too you'll need to extract the data into a data.frame:
bezlist = list()
for (i in 1:(length(x) - 1)) {
bezlist[[i]] = bezf(x1 = x[i], x2 = x[i + 1], y1 = y[i], y2 = y[i + 1], delta = 0.1)
}
xx = unlist(lapply(bezlist, FUN = '[', 'y'))
yy = unlist(lapply(bezlist, FUN = '[', 'y'))
bezdat = data.frame(react = xx, E = yy)
library(ggplot2)
ggplot(bezdat, aes(x = react, y = E)) +
geom_line() +
labs(x = "Reaction coordinate")
You could use a spline fit. Define some points along the energy diagram, and then fit to them using a spline function. The more points that you provide, the better that your fit will be. You can check out the smooth.splines function in the stats package for one implementation of the spline fit.

Plotting two Poisson processes on one plot

I have two Poisson processes:
n <- 100
x <- seq(0, 10, length = 1000)
y1 <- cumsum(rpois(1000, 1 / n))
y2 <- -cumsum(rpois(1000, 1 / n))
I would like to plot them in one plot and expect that y1 lies above x-axis and y2 lies below x-axis. I tried the following code:
plot(x, y1)
par(new = TRUE)
plot(x, y2, col = "red",
axes = FALSE,
xlab = '', ylab = '',
xlim = c(0, 10), ylim = c(min(y2), max(y1)))
but it did not work. Can someone please tell me how to fix this? (I am working with R for my code)
Many thanks in advance
How about
plot(x,y1, ylim=range(y1,y2), type="l")
lines(x, y2, col="red")
I would suggest trying to avoid multiple calls to plot with par(new=TRUE). That is usually very messy. Here we use lines() to add to an existing plot. The only catch is that the x and y limits won't change based on the new data, so we use ylim in the first plot() call to set a range appropriate for all the data.
Or if you don't want to worry about limits (like MrFlick mentioned) or the number of lines, you could also tide up your data and using melt and ggplot
df <- data.frame(x, y1, y2)
library(reshape2)
library(ggplot2)
mdf <- melt(df, "x")
ggplot(mdf, aes(x, value, color = variable)) +
geom_line()

Resources