inahull() not returning a right answer - r

When I use the alphahull library for determining whether a point belongs to a alpha-convex hull or not (inahull), I'm getting a FALSE for points that are clearly inside the alpha convex hull. I've tried different ways of handling the data but it seems that inahull doesn't work properly (or I don't know how to use it ;) )
library(alphahull)
data<-read.table("f2",h=T)
plot(x=x$alpha,y=x$beta, log="y")
Now, I select a set of points for creating a subspace in the plot
sp<-locator(30, type='p', pch=20)
sp
$x
[1] 16.91776 24.41393 36.14421 46.46116 43.34893 27.61219 16.99911
$y
[1] 31.74403 55.32414 68.87334 30.98970 15.31316 11.20075 15.14894
hull<-ahull(sp,alpha=1000)
Now, I add them to the plot just to check:
plot(hull, add=T)
(So far it looks good)
Now, if I check that these points are inside the shape (which are clearly inside):
inahull(hull, c(30,40))
FALSE
The data that I'm using can be found in this link:
https://drive.google.com/file/d/0B8gPXQL4u-b_c2RxNHNGcE5TOVk/edit?usp=sharing
A problem using alphahull was also reported here:
Row ordering for polygons
Thanks for your time and help!

Related

Reducing number of datapoints when plotting in loglog scale in Gnuplot

I have a large dataset which I need to plot in loglog scale in Gnuplot, like this:
set log xy
plot 'A_1D_l0.25_L1024_r0.dat' u 1:($2-512)
LogLogPlot of my datapoints
Text file with the datapoints
Datapoints on the x axis are equally spaced, but because of the logscale they get very dense on the right part of the graph, and as a result the output file (I finally export it in .tex) gets very large.
In linear scale, I would simply use the option every to reduce the number of points which get plotted. Is there a similar option for loglogscale, such that the plotted points appear equally spaced?
I am aware of a similar question which was raised a few years ago, but in my opinion the solution is unsatisfactory: plotted points are not equally spaced along the x-axis. I think this is a really unsophisticated problem which deserves a clearer solution.
As I understand it, you don't want to plot the actual data points; you just want to plot a line through them. But you want to keep the appearance of points rather than a line. Is that right?
set log xy
plot 'A_1D_l0.25_L1024_r0.dat' u 1:($2-512) with lines dashtype '.' lw 2
Amended answer
If it is important to present outliers/errors in the data set then you must not use every or any other technique that simply discards or skips most of the data points. In that case I would prefer the plot with points that you show in the original question, perhaps modified to represent each point as a dot rather than a cross. I will simulate this by modifying a single point in your 500000 point data set (first figure below). But I would also suggest that the presence of outliers is even more apparent if you plot with lines (second figure below).
Showing error bounds is another alternative for noisy data, but the options depend on what you have to work with in your data set. If you want to pursue that, please ask a separate question.
If you really want to reduce the number of data to be plotted, you might consider the following script.
s = 0.1 ### sampling interval in log scale
### (try 0.05 for more detail)
c = log10(0.01) ### a parameter used in sampler(x)
### which should be initialized by
### smaller value than any x in log scale
sampler(x) = (x>0 && log10(x)>=c) ? (c=ceil(log10(x)/s+0.5)*s, x) : NaN
set log xy
set grid xtics
plot 'A_1D_l0.25_L1024_r0.dat' using (sampler($1)):($2-512) with points pt 7 lt 1 notitle , \
'A_1D_l0.25_L1024_r0.dat' using 1:($2-512) with lines lt 1 notitle
This script samples the data in increments of roughly 0.1 on x-axis in log scale. It makes use of the property that points whose x value is evaluated as NaN in using are not drawn.

Area of polygon in ordiellipse is NaN - why?

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.

Remove holes in polygon

I am trying to solve the following problem in R :
I have a polygon object defined by a list l with two components x and y. The order defines the edges of the polygon.
For instance :
l=list(
x=c(-1.93400738955091,0.511747161547164,1.85047596846401,-1.4963460488281,-1.31613255558929,-0.0803828876660542,1.721752044722,-0.724002506376074,-2.08847609804132,2.13366860069641),
y=c(-1.02967154136169,1.53216851658359,-1.39564869249673,-1.21266011692921,1.6419616619241,-1.87141898897228,0.946605074767527,1.49557080147009,0.324443917837958,-0.517303529772633)
)
plot(l,type="b",pch=16)
points(l$x[c(10,1)],l$y[c(10,1)],type="b",pch=16)
Now what I am interested in is to keep only the outer boundary (but not the convex hull) of this polygon. The following picture highlights the point I'd like to keep
points(
x=c(-1.13927707377209,-1.31613255249992,-1.3598262571216,0.511747159281619,0.264900107013767,0.671727215417383,-0.724002505140328,-1.93400738893304,-1.4811931364624,-1.45298543105533,-2.08847609804132,-1.40787406113029,-1.3598262571216,0.278826441754518,1.85047596733123,1.48615105742673,1.48615105742673,2.13366860069641,1.38016944537233,1.38016944537233,1.17232981688283,1.17232981688283,1.72175204307433,0.671727215417383,-1.496346, -0.08038289, -0.2824999),
y=c(1.13914087952916,1.64196166071069,0.949843643913108,1.53216851597378,1.27360509238768,1.18229006681548,1.49557080106148,-1.02967154055378,-0.972634663817139,-0.525818314106921,0.324443915423533,0.188755761926866,0.949843643913108,-1.30971824545964,-1.3956486896768,-0.59886540309968,-0.59886540309968,-0.517303527559411,-0.367082245352325,-0.367082245352325,0.0874657083966551,0.0874657083966551,0.94660507315481,1.18229006681548,-1.21266,-1.871419,-1.281255),
pch=16,
col="red",
cex=0.75
)
I am really clueless about whether there are tools to easily do that. The closest I have found is the polysimplify function in the polyclip package, which identifies all the points I need, but also outputs some points I do not need (inner points where segments intersect).
I actually found a solution (below). The following function does what I want but I am unsure why it works (and whether it may fail).
Actually the function below correctly identifies the point I want but outputs them in the wrong order, so it is still useless to me...
polygon.clean<-function(poly){
require(polyclip)
poly.cleaned=polysimplify(poly)
x=unlist(sapply(poly.cleaned,function(x)x$x))
y=unlist(sapply(poly.cleaned,function(x)x$y))
x.src=x[!x%in%x[duplicated(x)]]
y.src=y[!y%in%y[duplicated(y)]]
poly.cleaned=poly.cleaned[sapply(poly.cleaned,function(poly.sub,x,y){
any(poly.sub$x%in%x&poly.sub$y%in%y)
},x=x.src,y=y.src)]
x=unlist(sapply(poly.cleaned,function(x){
res=x$x
if(length(res)==4){
res=vector()
}
res
}))
y=unlist(sapply(poly.cleaned,function(x){
res=x$y
if(length(res)==4){
res=vector()
}
res
}))
x=c(x,x.src)
y=c(y,y.src)
tester=duplicated(x)&duplicated(y)
x=x[!tester]
y=y[!tester]
list(x=x,y=y)
}
plot(l,type="b",pch=16)
points(l$x[c(10,1)],l$y[c(10,1)],type="b",pch=16)
points(polygon.clean(l),pch=16,cex=0.75,col="red")
Using rgeos routines, you first "node" your linestring to create all the intersections, then "polygonize" it, then "union" it to dissolve its insides.
First make a SpatialLines version of your data with duplicated first/last point:
library(sp)
library(rgeos)
coords = cbind(l$x, l$y); coords=rbind(coords,coords[1,])
s = SpatialLines(list(Lines(list(Line(coords)),ID=1)))
Then:
s_outer = gUnaryUnion(gPolygonize(gNode(s)))
Plot it thus:
plot(s,lwd=5)
plot(s_outer, lwd=2,border="red",add=TRUE)
If you want the coordinates of the surrounding polygon they are in the returned object and can be extracted with:
s_outer#polygons[[1]]#Polygons[[1]]#coords
# x y
# [1,] 0.27882644 -1.30971825
# [2,] -0.08038289 -1.87141899
# [3,] -0.28886517 -1.27867953
Assuming there's only one polygon, which might not be the case - suppose your line traces a figure-of-eight - then you'll get two polygons touching at a point. We don't know how free your jaggly line is to do things like that...

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")

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