I need to get the x- and y-coordinates of points along a Bezier curve in R. I thought this would work:
x <- c(0, 0, 1, 1)
y <- c(0, 1, 1, 0)
bg <- bezierGrob(x, y)
trace <- bezierPoints(bg)
But after running that trace$x and trace$y are a bunch of measurements in inches well outside the range of (0,1). The man page for bezierPoints says:
Rather than drawing an Xspline (or Bezier curve), this function returns the points that would be used to draw the series of line segments for the Xspline.
Am I running into some grid weirdness? Or am I trying to use the wrong solution to this problem?
Looks like the bezier package, not grid, is the way to go. This works:
t <- seq(0, 1, length=100)
p <- matrix(c(0,0, 0,1, 1,1, 1,0), nrow=4, ncol=2, byrow=TRUE)
bp <- bezier(t=t, p=p)
Related
Is it possible to draw real solid circle with a radius in "user" coordinates?
I tried the following:
Polygons:
I don't want to use them because I need real circles in the resulting svg.
Segments
segments(x, y, x, y, lwd=px, lend=0)
With segments there is the problem that I don't find a way to specify the segment in "user" coordinates.
The resulting graph is at the end exported to PDF.
Update
I draw a graph with a lot of elements and the elements has a distinct width. The width of the elements depends on the width at the x-axis. If I don't use user coordinates the result in the PDF is not correct in dependence to the x-axis.
A Polygon is an approximation to a circle and if I use them the result e.g. PDF is very large and the performance is not good and memory usage is very high. I draw 10,000 circles and more on one graph.
I use the following code with the described performance problems:
circle <- function(x, y, r, col) {
edgeCount <- 50
intervals <- (1:edgeCount) / edgeCount * 2 * pi
for(i in 1:length(x)) {
polygon(r[i]*sin(intervals) + x[i], r[i]*cos(intervals) + y[i], col=col[i],border=NA)
}
}
If you're comfortable with using a wrapper for sp's SpatialLine object you can try the oceanmap package which has a quite useful function called SpatialCircle(). It essentially builds a circle via seq() and adjusts it for your center point coordinates x and y, and for your radius r. It's still a set of line segments (so not one curved line), but quite simple to use.
Result:
Code:
Pretty straightforward:
# Load libraries.
library(oceanmap)
# Generate plot window and data.
set.seed(1702)
plot.new()
plot.window(xlim = c(0, 20), ylim = c(0, 10),
asp = 1, xaxs = "i", yaxs = "i")
axis(1)
axis(2)
box()
n <- 1000
x <- runif(n, 0, 20)
y <- runif(n, 0, 10)
for (i in 1:n) {
circle <- SpatialCircle(x = x[i], y = y[i], r = 0.1, n = 1000)
lines(circle)
}
This also works with ggplot2 with some data wrangling.
Addendum: Precision of SpatialCircles
If you want to check out what n (precision) in the SpatialCircle() function really means, try the following:
nrow(circle#lines[[1]]#Lines[[1]]#coords)
Result:
[1] 1000
This means that the object has 1,000 coordinate pairs (x and y) through which a line can be drawn. Furthermore, this line will have 999 distinct line segments, as the first and the last coordinate pairs are always identical. Proof:
all.equal(circle#lines[[1]]#Lines[[1]]#coords[1, ],
circle#lines[[1]]#Lines[[1]]#coords[1000, ])
Result:
[1] TRUE
If found a solution myself with the help of Gregor2 which did lead me to the library "grid".
library(grid)
#draw frame using normal plot
plot(0, 0, cex=0)
margins <- par("mar")
#1: bottom 2:left 3:top 4:right
mb <- unit(margins[1], "lines")
ml <- unit(margins[2], "lines")
mt <- unit(margins[3], "lines")
mr <- unit(margins[4], "lines")
#create viewport equivalent to margins in par
pushViewport(viewport(x = ml, y = mb, width = unit(1, "npc") - ml - mr, height = unit(1, "npc") - mb - mt, just=c("left", "bottom"), clip=TRUE))
#draw circle in npc units (easily convertable to user units using grconvertX)
grid.draw(circleGrob(x=0.5, y=0.5, r=0.5, default.units="npc", gp=gpar(col="blue", fill="blue")))
popViewport()
I have asked another question, which was closed as Too Broad. Now, I will try to specify.
Again, I would like to simulate a 1-dimensional point process in R. So far, I've only been working on 2-dimensional simulations and would need a bit of help.
My goal is a simulation like in the picture
But, I only need the real line with the random points on it.
I use spatstat and have already found out that I can generate random points on a 1-dim Line with:
rpoisppOnLines(lambda, L, lmax = NULL, ..., nsim=1, drop=TRUE)
Now, I would like to produce the real line, preferably with matching labeling.
Does anyone have an idea?
Here is some crude code on getting samples from a point process.
library(spatstat)
lambda = 5
L = psp(0, 0, 3, 0, owin(c(0, 3), c(-1, 1)))
pp = rpoisppOnLines(lambda, L, lmax = NULL, nsim=1, drop=TRUE)
plot(pp$x, pp$y, pch = 4, lwd = 2, cex = 2)
abline(0, 0)
You could make your plot fancy with ggplot2
You could use a simple linear network to represent the one dimensional line
segment you want to simulate on. This also makes it possible to fit models
(lppm), estimate the intensity non-parametrically (density.lpp), estimate
the K-function (linearK), and a bunch of other things:
library(spatstat)
x_start <- 0
x_end <- 3
endpoints <- ppp(x=c(x_start, x_end), y=c(0,0), window = owin(c(x_start, x_end), c(-.1,.1)))
L <- linnet(endpoints, edges = matrix(c(1,2),ncol = 2))
X <- rpoislpp(lambda = 5, L = L)
However, this tool is designed for points on a complicated network and not
just the real line, so the plotting method is not really adapted to this
setting, and might not produce exactly what you want (too much white space):
plot(X, pch = 4, lwd = 2, main = "")
axis(1)
You can extract the coordinates of the point pattern using coords and then
use the plotting method from the other answer from there:
co <- coords(X)
co$x
#> [1] 1.3306861 2.5550691 1.7776248 2.9486675 1.8571362 2.5020587 1.4843001
#> [8] 0.4371669 0.8478670
Created on 2018-12-18 by the reprex package (v0.2.1)
I have a fairly complex problem that I don't really know where to start. I have a set of spatial points (X & Y) coordinates that also include information (Height).
set.seed(12345)
X = runif(100, 0, 45)
Y = runif(100, 0, 45)
Height = runif(100, 6, 9)
data <- data.frame("X" = X, "Y" = Y, "Height" = Height)
data$Radius_max = 1/3 * data$Height
The coordinates look something like this:
ggplot(data, aes(X, Y)) +
geom_point()
For each point, I need a buffer that is scaled by Height. The buffer is an equation that is scaled by height but is essentially a circular buffer similar to a cone. The following steps are what I've come up with to determine buffer size for each point:
Set bottom left point to radius_max.
Find the intersection of the radius at any given point relative to the next point.
Do this multiple times to refit a new radius for the intial point relative to new adjacent radii.
The reason for starting at an initial point is that each radii following will be constrained by the neighboring points (randomly generating points may or may not have this effect). No cone can be below another cone. Think trees. If possible, I would like to know the radius at 45 degree increments.
I'm ok with any solution and suspect there may be a way to do this with the spatial packages rather than doing some by hand. Where do I start?
I am not quite sure what you are after. Particularly the 45 degrees increments. Do you want the buffer to be circular? If so, perhaps the below is a solution.
Your example data
set.seed(12345)
X <- runif(100, 0, 45)
Y <- runif(100, 0, 45)
Height <- runif(100, 6, 9)
data <- data.frame("X" = X, "Y" = Y, "Height" = Height)
data$Radius_max <- 1/3 * data$Height
Possible solution
library(raster)
x <- pointDistance(data[,1:2], lonlat=FALSE)
diag(x) <- NA
mn <- apply(x, 1, min, na.rm=TRUE)
data$radius <- pmin(data$Radius_max, mn/2)
d <- SpatialPoints(data[, c('X', 'Y')], proj4string=CRS('+proj=utm +zone=1'))
b <- buffer(d, data$radius, dissolve=FALSE)
plot(b)
I have a grid of rectangles, whose coordinates are stored in the variable say, 'gridPoints' as shown below:
gridData.Grid=GridTopology(c(min(data$LATITUDE),min(data$LONGITUDE)),c(0.005,0.005),c(32,32));
gridPoints = as.data.frame(coordinates(gridData.Grid))[1:1000,];
names(gridPoints) = c("LATITUDE","LONGITUDE");
plot(gridPoints,col=4);
points(data,col=2);
When plotted, these are the black points in the image,
Now, I have another data set of points called say , 'data', which when plotted are the blue points above.
I would want a count of how many blue points fall within each rectangle in the grid. Each rectangle can be represented by the center of the rectangle, along with the corresponding count of blue points within it in the output. Also, if the blue point lies on any of the sides of the rectangle, it can be considered as lying within the rectangle while making the count. The plot has the blue and black points looking like circles, but they are just standard points/coordinates and hence, much smaller than the circles. In a special case, the rectangle can also be a square.
Try this,
x <- seq(0,10,by=2)
y <- seq(0, 30, by=10)
grid <- expand.grid(x, y)
N <- 100
points <- cbind(runif(N, 0, 10), runif(N, 0, 30))
plot(grid, t="n", xaxs="i", yaxs="i")
points(points, col="blue", pch="+")
abline(v=x, h=y)
binxy <- data.frame(x=findInterval(points[,1], x),
y=findInterval(points[,2], y))
(results <- table(binxy))
d <- as.data.frame.table(results)
xx <- x[-length(x)] + 0.5*diff(x)
d$x <- xx[d$x]
yy <- y[-length(y)] + 0.5*diff(y)
d$y <- yy[d$y]
with(d, text(x, y, label=Freq))
A more general approach (may be overkill for this case, but if you generalize to arbitrary polygons it will still work) is to use the over function in the sp package. This will find which polygon each point is contained in (then you can count them up).
You will need to do some conversions up front (to spatial objects) but this method will work with more complicated polygons than rectangles.
If all the rectangles are exactly the same size, then you could use k nearest neighbor techniques using the centers of the rectangles, see the knn and knn1 functions in the class package.
Example
Suppose I have two triangles:
A triangle with points (0, 0), (10, 0), (10, 0.5) and
a triangle with points (0, 0), (1, 0), (0.5, 11)
The resulting two plots without specifying the xlim and ylimlook like this:
Question
What do I need to do to satisfy all points listed below?
Make the triangle visible, so that no line of the triangle is hidden by an axis
Specify the same margin for all plots in mm, cm or other unit.
(in the example above only two triangles were used. Actually I have n triangles.)
As margin I mean the distance between the outer points of the triangle and the axis.
The resulting plots should look like this
with the difference that the distances, which are marked with the red arrows, should all be the same!
I don't know of a way to to it in cm/mm, but you can do it with the precentage of the total size:
# you don't really need this see bellow
#from matplotlib.backends.backend_pdf import PdfPages
import pylab
import matplotlib.pyplot as plt
left,bottom,width,height = 0.2,0.1,0.6,0.6 # margins as % of canvas size
fig = plt.figure(figsize=(4,4),facecolor="yellow") # figure size in Inches
fig.patch.set_alpha(0.8) # just a trick so you can see the difference
# between the "canvas" and the axes
ax1 = plt.Axes(fig,[left,bottom,width,height])
ax1.plot([1,2,3,4],'b') # plot on the first axes you created
fig.add_axes(ax1)
ax1.plot([0,1,1,0,0], [0,0,1,1,0],"ro") # plot on the first axes you created
ax1.set_xlim([-1.1,2])
ax1.set_ylim([-1.1,2])
# pylab.plot([0,1,1,0,0], [0,0,1,1,0],"ro") avoid usig if you
# want to control more frames in a plot
# see my answer here
#http://stackoverflow.com/questions/8176458/\
#remove-top-and-right-axis-in-matplotlib-after-\
#increasing-margins/8180844#8180844
# pdf = PdfPages("Test.pdf")# you don't really need this
# pylab.savefig(pdf, papertype = "a4", format = "pdf")
# automagically make your pdf like this
pylab.savefig("Test1.pdf", papertype="a4",facecolor='y')
pylab.show()
pylab.close()
# pdf.close()
and the output is:
corrected image:
Your two triangles with points (0, 0), (10, 0), (10, 0.5) and (0, 0), (1, 0), (0.5, 11) would be represented in pylab as:
Ax = [0, 10, 10]
Ay = [0, 0, 0.5]
Bx = [0, 1, 0.5]
By = [0, 0, 11]
pylab.plot(Ax, Ay)
pylab.plot(Bx, By)
Let's see what the lowest X value is:
lowestX = None
for x in Ax+Bx:
if lowestX==None or x<lowestX:
lowestX = x
Exercise for the reader to do the same for highestX, lowestY, and highestY.
Now, consider a boundary of 2 units, you can add / subtract these units from the lowest and highest values and set xlim and ylim:
margin = 2
pylab.xlim([lowestX-margin, highestX+margin])
pylab.ylim([lowestY-margin, highestY+margin])