Area of polygon in ordiellipse is NaN - why? - r

I'm trying to add ellipses onto my NMDS plot created with Vegan package on R, but although the code goes through without an error, no polygons get drawn onto my graph. After using the summary() function, I found that the area of the polygon is NaN, hence why no polygons get drawn. I'm not sure why I don't have an area - is it something to do with my data?
My data can be found here: https://docs.google.com/spreadsheets/d/1uxWbKAvhdVqnorIMXURvYLrDZuoqejJpUsc9N6wSDxA/edit?usp=sharing
Three transects were done in three types of habitat - Interior forest, edge of the forest and disturbed habitat. Each dragonfly and damselfly seen was counted.
My R code is as follows:
OdonateNMDSdata <- read.csv(file.choose(), header=TRUE)
Odonaterownames <- row.names(OdonateNMDSdata) <- c("Interior", "Edge", "Disturbed")
library(vegan)
OdonateNMDS <- metaMDS(OdonateNMDSdata, k=2)
ordiplot(OdonateNMDS,type="n")
orditorp(OdonateNMDS,display="species",col="red",air=0.01)
orditorp(OdonateNMDS,display="sites",cex=1.25,air=0.01)
Ellipse <- ordiellipse(OdonateNMDS, groups=Odonaterownames, kind = "ehull", draw="polygon", col="blue", cex=0.7, conf=0.95)
summary(Ellipse)
Thanks

You have three points, and you want to draw three ellipses, one for each point. You need more than one point for each ellipse (and even for two points the enclosing ellipse would be a line connecting the points).
However, it seems that with enclosing ellipse (kind = "ehull") we give NaN as the area of one-point-ellipse, whereas with other kinds we give the area as 0 for one point. I'll change that.

Related

Trying to find point of intersection using approx function, results are correct on y but off on x axis

Working in R, I am attempting to plot stream cross sections, interpolate a point at an intersection opposite an identified "bankful" point, and calculate the area under the bankful line. It is part of a loop that is processing many cross sections. The best solution I have come up with is using the approx function, however all of the points are not exactly on the point of intersection and I have not been able to figure out what I am doing wrong.
It is hard to provide sample data since it is part of a loop, but the sample of code below produces the result in the image. The blue triangle is supposed to be at the point of intersection between the dashed "bankful" line and the solid cross section perimeter line.
###sample data
stn.sub.sort <- data.frame(dist = c(0,1.222,2.213,2.898,4.453,6.990,7.439,7.781,8.753,10.824,10.903,13.601,17.447), depth=c(-0.474,-0.633,0,-0.349,-1.047,-2.982,-2.571,-3.224,-3.100,-3.193,-2.995,-0.065,-0.112), Bankful = c(0,0,0,0,1,0,0,0,0,0,0,0,0))
###plot cross section with identified bankful
plot(stn.sub.sort$dist,
as.numeric(stn.sub.sort$depth),
type="b",
col=ifelse(stn.sub.sort$Bankful==1,"red","black"),
ylab="Depth (m)",
xlab="Station (m)",
ylim=range(stn.sub.sort$depth),
xlim=range(stn.sub.sort$dist),
main="3")
###visualize bankful line of intersection
abline(h=stn.sub.sort$depth[stn.sub.sort$Bankful==1],
lty=2,
col="black")
###approximate point at intersection
index.bf=which(stn.sub.sort$Bankful==1)
index.approx<-which(stn.sub.sort$dist>stn.sub.sort$dist[index.bf])
sbf <- approx(stn.sub.sort$depth[index.approx],
stn.sub.sort$dist[index.approx],
xout=stn.sub.sort$depth[index.bf])
###plot opposite bankful points
points(sbf$y,sbf$x,pch=2,col="blue")
So your description leaves many questions about the nature of the data that you will have to deal with. I am going to assume that it will be roughly like your example - down from the first bankful point, then going back up with the curve crossing the depth of the bankful point just one more time.
With that assumption, it is easy to find the point before and the point after the crossing point. You just need to draw the line between those two points and solve for the correct dist value. I do this below by using approxfun to get the inverse function of the line connecting the two points. Then we can just plug in to get the dist-value of the crossing point.
BankfulDepth = stn.sub.sort$depth[stn.sub.sort$Bankful==1]
Low = max(which(stn.sub.sort$depth < BankfulDepth))
InvAF = approxfun(stn.sub.sort$depth[c(Low,Low+1)],
stn.sub.sort$dist[c(Low,Low+1)])
points(InvAF(BankfulDepth), BankfulDepth, pch=2,col="blue")

R - locate intersection of two curves

There are a number of questions in this forum on locating intersections between a fitted model and some raw data. However, in my case, I am in an early stage project where I am still evaluating data.
To begin with, I have created a data frame that contains a ratio value whose ideal value should be 1.0. I have plotted the data frame and also used abline() function to plot a horizontal line at y=1.0. This horizontal line and the plot of ratios intersect at some point.
plot(a$TIME.STAMP, a$PROCESS.RATIO,
xlab='Time (5s)',
ylab='Process ratio',
col='darkolivegreen',
type='l')
abline(h=1.0,col='red')
My aim is to locate the intersection point, say x and draw two vertical lines at x±k, as abline(v=x-k) and abline(v=x+k) where, k is certain band of tolerance.
Applying a grid on the plot is not really an option because this plot will be a part of a multi-panel plot. And, because ratio data is very tightly laid out, the plot will not be too readable. Finally, the x±k will be quite valuable in my discussions with the domain experts.
Can you please guide me how to achieve this?
Here are two solutions. The first one uses locator() and will be useful if you do not have too many charts to produce:
x <- 1:5
y <- log(1:5)
df1 <-data.frame(x= 1:5,y=log(1:5))
k <-0.5
plot(df1,type="o",lwd=2)
abline(h=1, col="red")
locator()
By clicking on the intersection (and stopping the locator top left of the chart), you will get the intersection:
> locator()
$x
[1] 2.765327
$y
[1] 1.002495
You would then add abline(v=2.765327).
If you need a more programmable way of finding the intersection, we will have to estimate the function of your data. Unfortunately, you haven’t provided us with PROCESS.RATIO, so we can only guess what your data looks like. Hopefully, the data is smooth. Here’s a solution that should work with nonlinear data. As you can see in the previous chart, all R does is draw a line between the dots. So, we have to fit a curve in there. Here I’m fitting the data with a polynomial of order 2. If your data is less linear, you can try increasing the order (2 here). If your data is linear, use a simple lm.
fit <-lm(y~poly(x,2))
newx <-data.frame(x=seq(0,5,0.01))
fitline = predict(fit, newdata=newx)
est <-data.frame(newx,fitline)
plot(df1,type="o",lwd=2)
abline(h=1, col="red")
lines(est, col="blue",lwd=2)
Using this fitted curve, we can then find the closest point to y=1. Once we have that point, we can draw vertical lines at the intersection and at +/-k.
cross <-est[which.min(abs(1-est$fitline)),] #find closest to 1
plot(df1,type="o",lwd=2)
abline(h=1)
abline(v=cross[1], col="green")
abline(v=cross[1]-k, col="purple")
abline(v=cross[1]+k, col="purple")

GraphPad Mann Whitney scatter plot in R

I try to make a plot similar to the top three plot of this:
I found a partial answer here, however I am unsure how to add the p-values in the scatter-plot.
Any tips?
You've already got a partial answer. If you just want to know how to put p-values on then use text. (looking at graph C).
text(x = 1.5, y = 73, 'p = 0.03')
If you want the p-values and the lines underneath, assuming you also want those caps on the lines, use arrows instead of segments.
arrows(1, 70, 2, length = 2, angle = 90, code = 3)
If you're sticking with solving this in base R that's a great learning exercise and can give you full control over your plot. However, if you just want to get it done I'd suggest the beeswarm package (you're making beeswarm plots).
As an aside, this prompted me to investigate why you get those upward curving lines in beeswarm plots. It's a consequence of the typical algorithm. The line curves upward because the positions are calculated through increasing y-values. If the next y-value is so close that the points would overlap in the y-axis it's plotted at an angle off the x position. Many points close together on Y results in upward curving lines until you get far enough along Y to go back to X. Smaller points should alleviate that. Also, the beeswarm package in R has several optional algorithms that avoid that as well.

Plotting lines between two points in 3D

I am writing an regression algorithm which tries to "capture" points inside boxes. The algorithm tries to keep the boxes as small as possible, so usually the edges/corners of the boxes go through points, which determines the size of the box.
Problem: I need graphical output of the boxes in R. In 2D it is easy to draw boxes with segments(), which draws a line between two points. So, with 4 segments I can draw a box:
plot(x,y,type="p")
segments(x1,y1,x2,y2)
I then tried both the scatterplot3d and plot3d package for 3D plotting. In 3D the segments() command is not working, as there is no additional z-component. I was surprised that apparently (to me) there is no adequate replacement in 3D for segments()
Is there an easy way to draw boxes / lines between two points when plotting in three dimensions ?
The scatterplot3d function returns information that will allow you to project (x,y,z) points into the relevant plane, as follows:
library(scatterplot3d)
x <- c(1,4,3,6,2,5)
y <- c(2,2,4,3,5,9)
z <- c(1,3,5,9,2,2)
s <- scatterplot3d(x,y,z)
## now draw a line between points 2 and 3
p2 <- s$xyz.convert(x[2],y[2],z[2])
p3 <- s$xyz.convert(x[3],y[3],z[3])
segments(p2$x,p2$y,p3$x,p3$y,lwd=2,col=2)
The rgl package is another way to go, and perhaps even easier (note that segments3d takes points in pairs from a vector)
plot3d(x,y,z)
segments3d(x[2:3],y[2:3],z[2:3],col=2,lwd=2)

Make a 3D rendered plot of time-series

I have a set of 3D coordinates (below - just for a single point, in 3D space):
x <- c(-521.531433, -521.511658, -521.515259, -521.518127, -521.563416, -521.558044, -521.571228, -521.607178, -521.631165, -521.659973)
y <- c(154.499557, 154.479568, 154.438705, 154.398682, 154.580688, 154.365189, 154.3564, 154.559189, 154.341309, 154.344223)
z <- c(864.379272, 864.354675, 864.365479, 864.363831, 864.495667, 864.35498, 864.358582, 864.50415, 864.35553, 864.359863)
xyz <- data.frame(x,y,z)
I need to make a time-series plot of this point with a 3D rendering (so I can rotate the plot, etc.). The plot will visualize a trajectory of the point above in time (for example in the form of solid line). I used 'rgl' package with plot3d method, but I can't make it to plot time-series (below, just plot a single point from first frame in time-series):
require(rgl)
plot3d(xyz[1,1],xyz[1,2],xyz[1,3],axes=F,xlab="",ylab="",zlab="")
I found this post, but it doesn't really deal with a real-time rendered 3D plots. I would appreciate any suggestions. Thank you.
If you read help(plot3d) you can see how to draw lines:
require(rgl)
plot3d(xyz$x,xyz$y,xyz$z,type="l")
Is that what you want?
How about this? It uses rgl.pop() to remove a point and a line and draw them as a trail - change the sleep argument to control the speed:
ts <- function(xyz,sleep=0.3){
plot3d(xyz,type="n")
n = nrow(xyz)
p = points3d(xyz[1,])
l = lines3d(xyz[1,])
for(i in 2:n){
Sys.sleep(sleep)
rgl.pop("shapes",p)
rgl.pop("shapes",l)
p=points3d(xyz[i,])
l=lines3d(xyz[1:i,])
}
}
The solution was simpler than I thought and the problem was that I didn't use as.matrix on my data. I was getting error (list) object cannot be coerced to type 'double' when I was simply trying to plot my entire dataset using plot3d (found a solution for this here). So, if you need to plot time-series of set of coordinates (in my case motion capture data of two actors) here is my complete solution (only works with the data set below!):
download example data set
read the above data into a table:
data <- read.table("Bob12.txt",sep="\t")
extract XYZ coordinates into a separate matrixes:
x <- as.matrix(subset(data,select=seq(1,88,3)))
y <- as.matrix(subset(data,select=seq(2,89,3)))
z <- as.matrix(subset(data,select=seq(3,90,3)))
plot the coordinates on a nice, 3D rendered plot using 'rgl' package:
require(rgl)
plot3d(x[1:nrow(x),],y[1:nrow(y),],z[1:nrow(z),],axes=F,xlab="",ylab="",zlab="")
You should get something like on the image below (but you can rotate it etc.) - hope you can recognise there are joint centers for people there. I still need to tweak it to make it visually better - to have first frame as a points (to clearly see actor's joints), then a visible break, and then the rest of frames as a lines.

Resources