How to extend a line to touch a polygon? - r

I would like to extend line to touch polygon
Create line and polygon line and polygon
Here is my solution to "stretch and trim".
Turned out a bit trickier than the first "solution" I offered initially.
I also included cases for horizontal and vertical lines.
My example I think covers all cases (direction of lines)
I have the coding very simple , no effort to make it more efficient
library(sf)
#
s1 <- rbind(c(1, 2), c(2, 3))
ls1 <- st_linestring(s1)
s2 <- rbind(c(2, 2), c(1, 3))
ls2 <- st_linestring(s2)
s3 <- rbind(c(2, 2), c(1, 1))
ls3 <- st_linestring(s3)
s4 <- rbind(c(1, 2), c(2, 1)) # VERTICAL LINE
ls4 <- st_linestring(s4)
vl <- rbind(c(2.5, 2), c(2.5, 3))
svl <- st_linestring(vl)
hl <- rbind(c(0.5, 0.5), c(1, 0.5))
shl <- st_linestring(hl)
line <- st_multilinestring(list(ls1, ls2, ls3, ls4, svl, shl))
p1 <- rbind(c(0, 0), c(1, 0), c(3, 2), c(2, 4), c(1, 4), c(0, 0))
pol <- st_polygon(list(p1))
#
(
plot1 <- ggplot() +
geom_sf(data = ls1, col = 'red', size = 2) +
geom_sf(data = ls2, col = 'darkred', size = 2) +
geom_sf(data = ls3, col = 'blue', size = 2) +
geom_sf(data = ls4, col = 'darkblue', size = 2) +
geom_sf(data = svl, col = 'green', size = 2) +
geom_sf(data = shl, col = 'green', size = 2) +
geom_sf(data = pol, fill = NA)
)
####################### Function
line_stretchntrim <- function(line, polygon) {
if (st_crs(line) != st_crs(polygon))
return("CRS not matching")
bb <- st_bbox(polygon)
bbdiagLength <-
as.numeric(sqrt((bb$xmin - bb$xmax) ^ 2 + (bb$ymin - bb$ymax) ^ 2))
xy <- st_coordinates(line)[, 1:2]
npairs <- nrow(xy) / 2
etline <- NULL
for (i in 1:npairs) {
ii <- (i - 1) * 2 + 1
x <- as.numeric(xy[ii:(ii + 1), 1])
y <- as.numeric(xy[ii:(ii + 1), 2])
dxline <- diff(x)
dyline <- diff(y)
d <- sqrt(dxline ^ 2 + dyline ^ 2)
scale <- abs(as.numeric(bbdiagLength)) # * extra if need be
signx <- sign(dxline)
signy <- sign(dyline)
theta <- atan(dxline / dyline)
# expand
if (signy == 1) {
dx1 <- -sin(theta) * scale #* d
dy1 <- -cos(theta) * scale #* d
dx2 <- sin(theta) * scale #* d
dy2 <- cos(theta) * scale #* d
}
if (signy == -1) {
dx1 <- sin(theta) * scale# * d
dy1 <- cos(theta) * scale# * d
dx2 <- -sin(theta) * scale# * d
dy2 <- -cos(theta) * scale# * d
}
## Cases when dxline == 0 or dyline == 0
# dxline == 0
if ((dxline == 0) * (signy == -1)) {
dx1 <- 0
dy1 <- cos(theta) * scale# * d
dx2 <- 0
dy2 <- -cos(theta) * scale# * d
}
if ((dxline == 0) * (signy == 1)) {
dx1 <- 0
dy1 <- -cos(theta) * scale# * d
dx2 <- 0
dy2 <- cos(theta) * scale# * d
}
if ((signx == 1) * (dyline == 0)) {
dx1 <- -sin(theta) * scale# * d
dy1 <- 0
dx2 <- sin(theta) * scale# * d
dy2 <- 0
}
if ((signx == -1) * (dyline == 0)) {
dx1 <- sin(theta) * scale# * d
dy1 <- 0
dx2 <- -sin(theta) * scale# * d
dy2 <- 0
}
x1 <- x[1] + dx1
y1 <- y[1] + dy1
# second point shift
x2 <- x[2] + dx2
y2 <- y[2] + dy2
# construct spatial line
sline <- st_linestring(matrix(c(x1, y1, x2, y2),
byrow = TRUE, ncol = 2))
slineSf <- st_sf(geom = st_sfc(sline), crs = st_crs(polygon))
# Now trim to polygon
stline <- st_intersection(slineSf, polygon)
etline <- if (i == 1)
stline
else
rbind(etline, stline)
}
etline
}
stretched_line <- line_stretchntrim(line, pol)
#
ggplot() +
geom_sf(data = pol, fill = NA) +
geom_sf(data = line, size = 2) +
geom_sf(data = stretched_line)

Related

How to create a Matlab pumpkin in R?

I am trying to replicate the following visual with the following Matlab code:
% Pumpkin
[X,Y,Z]=sphere(200);
R=1-(1-mod(0:.1:20,2)).^2/12;
x=R.*X; y=R.*Y; z=Z.*R;
c=hypot(hypot(x,y),z)+randn(201)*.03;
surf(x,y,(.8+(0-(1:-.01:-1)'.^4)*.3).*z,c, 'FaceColor', 'interp', 'EdgeColor', 'none')
% Stem
s = [ 1.5 1 repelem(.7, 6) ] .* [ repmat([.1 .06],1,10) .1 ]';
[t, p] = meshgrid(0:pi/15:pi/2,0:pi/20:pi);
Xs = -(.4-cos(p).*s).*cos(t)+.4;
Zs = (.5-cos(p).*s).*sin(t) + .55;
Ys = -sin(p).*s;
surface(Xs,Ys,Zs,[],'FaceColor', '#008000','EdgeColor','none');
% Style
colormap([1 .4 .1; 1 1 .7])
axis equal
box on
material([.6 1 .3])
lighting g
camlight
I am working on the bottom but have not gotten very far (see here for reference). The code that I have is:
library(pracma)
library(rgl)
sphere <- function(n) {
dd <- expand.grid(theta = seq(0, 2*pi, length.out = n+1),
phi = seq(-pi, pi, length.out = n+1))
with(dd,
list(x = matrix(cos(phi) * cos(theta), n+1),
y = matrix(cos(phi) * sin(theta), n+1),
z = matrix(sin(phi), n+1))
)
}
# Pumpkin
sph<-sphere(200)
X<-sph[[1]]
Y<-sph[[2]]
Z<-sph[[3]]
R<- 1-(1-seq(from=0, to=20,by=0.1))^2/12
x<-R * X
y<-R * Y
z<-Z * R
c<-hypot(hypot(x,y),z)+rnorm(201)*0.3
persp3d(x,y,(0.8+(0-seq(from=1, to=-1, by=-0.01)^4)*0.3)*z,col=c)
and it gives me the following.
What is it that's going wrong in my present code? What would be a suggested fix?
As #billBokeey mentioned, there's a missing mod modulo operator function for periodic scaling factors.
In addition, the scaling on the z-axis 0.8 + (0-seq(from=1, to=-1, by=-0.01)^4) * 0.3 doesn't go well with the output from your sphere function. We maybe use Z[1,] to replace seq(from=1, to=-1, by=-0.01). phi = seq(-pi, pi, length.out = n+1)) shoud be seq(-pi/2, pi/2, length.out = n+1)) instead.
Finally, the color c needs to be convert to RGB code for persp3d.
Here's the result look like from the code below.
library(rgl)
sphere <- function(n) {
dd <- expand.grid(theta = seq(0, 2*pi, length.out = n+1),
phi = seq(-pi/2, pi/2, length.out = n+1))
with(dd,
list(x = matrix(cos(phi) * cos(theta), n+1),
y = matrix(cos(phi) * sin(theta), n+1),
z = matrix(sin(phi), n+1))
)
}
# Unit ball
sph <- sphere(200)
X <- sph[[1]]
Y <- sph[[2]]
Z <- sph[[3]]
# scaling
R <- 1 - (1 - seq(from=0, to=20, by=0.1) %% 2) ^ 2 / 12 # Modulo Operator %%
R2 <- 0.8 + (0 - seq(from=1, to=-1, by=-0.01)^4)*0.2 # didn't match with the order of z from sphere function
#R2 <- 0.8 - Z[1,]^4 * 0.2
x <- R * X # scale rows for wavy side
y <- R * Y # scale rows for wavy side
z <- t(R2 * t(Z)) # scale columns by transpose for flat oval shape
# color according to distance to [0,0,0]
hypot_3d <- function(x, y, z) {
return(sqrt(x^2 + y^2 + z^2))
}
c_ <- hypot_3d(x,y,z) + rnorm(201) * 0.03
color_palette <- terrain.colors(20) # color look-up table
col <- color_palette[ as.numeric(cut(c_, breaks = 20)) ] # assign color to 20 levels of c_
persp3d(x, y, z, color = col, aspect=FALSE)

Plotting fitted values from regression

Hey I have following code in R
S0 = 40
r = log(1 + 0.07)
sigma = 0.3
K = 45
n_steps_per_year = 4
dt = 1 / n_steps_per_year
T = 3
n_steps = n_steps_per_year * T
R = n_paths
Q = 70
P = 72
n_paths = P * Q
d = exp(-r * dt)
N = matrix(rnorm(n_paths * n_steps, mean = 0, sd = 1), n_paths, n_steps)
paths_S = matrix(nrow = n_paths, ncol = n_steps + 1, S0)
for(i in 1:n_paths){
for(j in 1:n_steps){
paths_S[i, j + 1] = paths_S[i, j] * exp((r - 0.5 * sigma ^ 2) * dt + sigma * sqrt(dt) * N[i, j])
}
}
I = apply(K - paths_S, c(1,2), max, 0)
V = matrix(nrow = n_paths, ncol = n_steps + 1)
V[, n_steps + 1] = I[, n_steps + 1]
dV = d * V[, n_steps + 1]
model = lm(dV ~ poly(paths_S[, n_steps], 10))
pred = predict(model, data.frame(x = paths_S[, n_steps]))
plot(paths_S[, n_steps], d * V[, n_steps + 1])
lines(paths_S[, n_steps], pred)
but when I run the last two lines then I get very strange plot (multiple lines instead of one line). What is going on?
You did not provide n_paths, lets assume:
n_paths = 7
set.seed(111)
Then running your code, before you plot, you need to order your x values before plotting:
o = order(paths_S[,12])
plot(paths_S[o, n_steps], d * V[o, n_steps + 1],cex=0.2,pch=20)
lines(paths_S[o, n_steps], pred[o],col="blue")

Changing branch length in dendrogram (pheatmap)

I am trying to plot a heatmap with the library pheatmap in R.
I think that by default the branch length is proportional to the "dissimilarity" of the clusters that got merged at this step. I would like to chance that, so it is a fixed value because for my purpose it looks very weird!
If anyone has an idea how I can fix this, I would be very happy.
Here is a sample code
library(pheatmap)
test = matrix(rnorm(6000), 100, 60)
pheatmap(test)
Cheers!
Here is an example of two column groups with high dissimilarity:
library(pheatmap)
test = cbind(matrix(rnorm(3000), 100, 30),
matrix(rnorm(3000)+10, 100, 30))
pheatmap(test)
TIn pheatmapthe dendrogram is plotted by the pheatmap:::draw_dendrogram function
and branch lengths are stored in the h object.
Below I define equal-length branches adding the command
hc$height <- cumsum(rep(1/length(hc$height), length(hc$height)))
as follows:
draw_dendrogram <- function(hc, gaps, horizontal = T) {
# Define equal-length branches
hc$height <- cumsum(rep(1/length(hc$height), length(hc$height)))
h = hc$height/max(hc$height)/1.05
m = hc$merge
o = hc$order
n = length(o)
m[m > 0] = n + m[m > 0]
m[m < 0] = abs(m[m < 0])
dist = matrix(0, nrow = 2 * n - 1, ncol = 2, dimnames = list(NULL,
c("x", "y")))
dist[1:n, 1] = 1/n/2 + (1/n) * (match(1:n, o) - 1)
for (i in 1:nrow(m)) {
dist[n + i, 1] = (dist[m[i, 1], 1] + dist[m[i, 2], 1])/2
dist[n + i, 2] = h[i]
}
draw_connection = function(x1, x2, y1, y2, y) {
res = list(x = c(x1, x1, x2, x2), y = c(y1, y, y, y2))
return(res)
}
x = rep(NA, nrow(m) * 4)
y = rep(NA, nrow(m) * 4)
id = rep(1:nrow(m), rep(4, nrow(m)))
for (i in 1:nrow(m)) {
c = draw_connection(dist[m[i, 1], 1], dist[m[i, 2], 1],
dist[m[i, 1], 2], dist[m[i, 2], 2], h[i])
k = (i - 1) * 4 + 1
x[k:(k + 3)] = c$x
y[k:(k + 3)] = c$y
}
x = pheatmap:::find_coordinates(n, gaps, x * n)$coord
y = unit(y, "npc")
if (!horizontal) {
a = x
x = unit(1, "npc") - y
y = unit(1, "npc") - a
}
res = polylineGrob(x = x, y = y, id = id)
return(res)
}
# Replace the non-exported function `draw_dendrogram` in `pheatmap`:
assignInNamespace(x="draw_dendrogram", value=draw_dendrogram, ns="pheatmap")
pheatmap(test)
The result is:

How to plot a CDF functon from PDF in R

I have the following function:
fx <- function(x) {
if(x >= 0 && x < 3) {
res <- 0.2;
} else if(x >=3 && x < 5) {
res <- 0.05;
} else if(x >= 5 && x < 6) {
res <- 0.15;
} else if(x >= 7 && x < 10) {
res <- 0.05;
} else {
res <- 0;
}
return(res);
}
How can I plot it's CDF function on the interval [0,10]?
Try
fx <- Vectorize(fx)
grid <- 0:10
p <- fx(grid)
cdf <- cumsum(p)
plot(grid, cdf, type = 'p', ylim = c(0, 1), col = 'steelblue',
xlab = 'x', ylab = expression(F(x)), pch = 19, las = 1)
segments(x0 = grid, x1 = grid + 1, y0 = cdf)
segments(x0 = grid + 1, y0 = c(cdf[-1], 1), y1 = cdf, lty = 2)
To add a bit accuracy to #Martin Schmelzer's answer. A cummulative distribution function(CDF)
evaluated at x, is the probability that X will take a value less than
or equal to x
So to get CDF from Probability Density Function(PDF), you need to integrate on PDF:
fx <- Vectorize(fx)
dx <- 0.01
x <- seq(0, 10, by = dx)
plot(x, cumsum(fx(x) * dx), type = "l", ylab = "cummulative probability", main = "My CDF")
Just adding up on the previous answers and using ggplot
# cdf
Fx <- function(x, dx) {
cumsum(fx(x)*dx)
}
fx <- Vectorize(fx)
dx <- 0.01
x <- seq(0, 10, dx)
df <- rbind(data.frame(x, value=fx(x), func='pdf'),
data.frame(x, value=Fx(x, dx), func='cdf'))
library(ggplot2)
ggplot(df, aes(x, value, col=func)) +
geom_point() + geom_line() + ylim(0, 1)

R-scatterplot3d rendering in Beaker Notebook

I'm trying to get the scatterplot3d package of R to render within a Beaker Notebook, but cannot get it to work. I can run the code without error, but the graphic is not displayed. Setting the scatterplot3d output to a variable and printing the variables gets:
input:
data(iris)
test <- scatterplot3d(iris[,1:3])
test
output:
$xyz.convert
function (x, y = NULL, z = NULL)
{
xyz <- xyz.coords(x, y, z)
if (angle > 2) {
temp <- xyz$x
xyz$x <- xyz$y
xyz$y <- temp
}
y <- (xyz$y - y.add)/y.scal
return(list(x = xyz$x/x.scal + yx.f * y, y = xyz$z/z.scal +
yz.f * y))
}
<environment: 0x00000000048f8830>
$points3d
function (x, y = NULL, z = NULL, type = "p", ...)
{
xyz <- xyz.coords(x, y, z)
if (angle > 2) {
temp <- xyz$x
xyz$x <- xyz$y
xyz$y <- temp
}
y2 <- (xyz$y - y.add)/y.scal
x <- xyz$x/x.scal + yx.f * y2
y <- xyz$z/z.scal + yz.f * y2
mem.par <- par(mar = mar, usr = usr)
on.exit(par(mem.par))
if (type == "h") {
y2 <- z.min + yz.f * y2
segments(x, y, x, y2, ...)
points(x, y, type = "p", ...)
}
else points(x, y, type = type, ...)
}
<environment: 0x00000000048f8830>
$plane3d
function (Intercept, x.coef = NULL, y.coef = NULL, lty = "dashed",
lty.box = NULL, ...)
{
if (!is.atomic(Intercept) && !is.null(coef(Intercept)))
Intercept <- coef(Intercept)
if (is.null(lty.box))
lty.box <- lty
if (is.null(x.coef) && length(Intercept) == 3) {
x.coef <- Intercept[if (angle > 2)
3
else 2]
y.coef <- Intercept[if (angle > 2)
2
else 3]
Intercept <- Intercept[1]
}
mem.par <- par(mar = mar, usr = usr)
on.exit(par(mem.par))
x <- x.min:x.max
ltya <- c(lty.box, rep(lty, length(x) - 2), lty.box)
x.coef <- x.coef * x.scal
z1 <- (Intercept + x * x.coef + y.add * y.coef)/z.scal
z2 <- (Intercept + x * x.coef + (y.max * y.scal + y.add) *
y.coef)/z.scal
segments(x, z1, x + y.max * yx.f, z2 + yz.f * y.max, lty = ltya,
...)
y <- 0:y.max
ltya <- c(lty.box, rep(lty, length(y) - 2), lty.box)
y.coef <- (y * y.scal + y.add) * y.coef
z1 <- (Intercept + x.min * x.coef + y.coef)/z.scal
z2 <- (Intercept + x.max * x.coef + y.coef)/z.scal
segments(x.min + y * yx.f, z1 + y * yz.f, x.max + y * yx.f,
z2 + y * yz.f, lty = ltya, ...)
}
<environment: 0x00000000048f8830>
$box3d
function (...)
{
mem.par <- par(mar = mar, usr = usr)
on.exit(par(mem.par))
lines(c(x.min, x.max), c(z.max, z.max), ...)
lines(c(0, y.max * yx.f) + x.max, c(0, y.max * yz.f) + z.max,
...)
lines(c(0, y.max * yx.f) + x.min, c(0, y.max * yz.f) + z.max,
...)
lines(c(x.max, x.max), c(z.min, z.max), ...)
lines(c(x.min, x.min), c(z.min, z.max), ...)
lines(c(x.min, x.max), c(z.min, z.min), ...)
}
<environment: 0x00000000048f8830>
I'm not sure if this functionality is possible with Beaker Notebooks, but thought I check here if anyone has any tips.
Thanks,
-pH+
it worked for me, just by making sure the library was loaded: https://pub.beakernotebook.com/#/publications/312f12ee-1619-11e6-8e18-afd4bf712b6e
Figured it out. As part of my code, I was changing the working directory of R to more easily pull in datafiles from my project folder via:
setwd("C:/Users/macle/Desktop/UPC Masters/Semester 1/CN/MAI-CN/Final Project")
It appears that somewhere along the way, this breaks the ability of scatterplot3d to display the output in a Beaker Notebook.
I've instead just used absolute paths to load the files I need, which has solved the issue for me.
#spot Thanks for pointing me in the right direction and confirming the issue was on my end and not a limitation of Beaker.
Ps. I love working with Beaker, thanks for developing such a fantastic tool.

Resources