Generación de una red hexagonal usando Spatstat
Frecuentes
Visto 1,432 equipos
3
Estoy analizando el patrón de crecimiento de ciertas partículas y quiero comparar el patrón de puntos con el de una red perfectamente hexagonal con la misma intensidad (mismo número de puntos por unidad de área). He escrito una función que hace esto, pero tiene un error inherente y no estoy seguro de dónde se origina. Esencialmente, después de que la función ha seguido su curso, produce un patrón de puntos perfectamente hexagonal que NO tiene el número correcto de partículas; por lo general, está desviado entre un 1 y un 4 %. Si copia y pega el siguiente código en R, verá esto (para este ejemplo en particular, el error es del 11.25 %): el patrón de puntos original tiene 71 partículas y el patrón de puntos perfectamente hexagonal que se generó tiene 80 partículas. Esto parece muy extraño, ya que el código, como verá, está diseñado para colocar las partículas a una distancia específica entre sí, creando así una ventana del mismo tamaño que la original con el mismo número de partículas.
El siguiente es el código de la función que escribí para generar la red hexagonal.
library(spatstat)
data(swedishpines)
swedishpines.df <- as.data.frame(swedishpines)
MaxXValue <- max(swedishpines.df[1])
MaxYValue <- max(swedishpines.df[2])
#The above two lines dictate the window size
NumberOfParticles <- nrow(swedishpines.df[1])
#Number of entries = number of particles
#calculate delta
intensity <- NumberOfParticles / (MaxXValue*MaxYValue)
#Intensity ---> particles / unit^2
#Area = ( sqrt(3) / 2 ) * delta^2
#Now - in substituting intensity in for area, it is key to recognize
#that there are 3 particles associated with each hexagonal tile.
#This is because each particle on the border of the tile is really 1/3 of a
#a particle due to it being associated with 3 different hexagonal tiles.
#Since intensity = 3 Particles / Area,
delta <- sqrt(2/(intensity*(sqrt(3))))
#This is derived from the equation for the area of a regular hexagon.
#xcoords and ycoords represent the x and y coordintes of all of the generated points. The 'x' and 'y' are temporary holders for the x and y coordinates of a single horizontal line of points (they are appended to xcoords and ycoords at the end of each while loop).
xcoords <- c()
ycoords <- c()
#The following large while loop calculates the coordinates of the first set of points that are vertically aligned with one another. (alternating horizontal lines of particles) This is shown in the image below.
y_shift <- 0
while (y_shift < MaxYValue) {
x <- c(0)
x_shift <- 0 + delta
count <- 0
while (x_shift < MaxXValue) {
x <- append(x, x_shift)
x_shift <- x_shift + delta
count <- count + 1
}
y <- c(y_shift)
for (i in seq(0,(count-1))) {
y <- append(y, y_shift)
}
y_shift <- y_shift + sqrt(3)*delta
xcoords <- append(xcoords,x)
ycoords <- append(ycoords,y)
}
#The following large while loop calculates the coordinates of the second set of points that are vertically aligned with one another. This is shown in the image below.
y_shift <- 0 + (delta*(sqrt(3)))/2
while (y_shift < MaxYValue) {
x <- c(0 + (1/2)*delta)
x_shift <- 0 + (1/2)*delta + delta
count <- 0
while (x_shift < MaxXValue) {
x <- append(x, x_shift)
x_shift <- x_shift + delta
count <- count + 1
}
y <- c(y_shift)
for (i in seq(0,(count-1))) {
y <- append(y, y_shift)
}
y_shift <- y_shift + sqrt(3)*delta
xcoords <- append(xcoords,x)
ycoords <- append(ycoords,y)
}
hexplot <- ppp(xcoords, ycoords, window=owin(c(0,MaxXValue),c(0,MaxYValue)))
Ahora, soy relativamente nuevo en R, por lo que puede ser un error de sintaxis en alguna parte del código que haya causado este error. O puede ser que tenga alguna falla en mi línea de pensamiento con este proceso. Sin embargo, no creo que eso sea probable, ya que mis resultados han estado bastante cerca de lo que he estado intentando (solo un error del 1 al 4 % la mayoría de las veces es bastante bueno).
En resumen, en lo que me gustaría recibir ayuda es en cómo tomar un patrón de puntos y crear otro patrón de puntos del mismo tamaño de ventana con el mismo número de partículas, pero un patrón de puntos perfectamente hexagonal.
Por favor, no dude en pedirme que aclare cualquier cosa si siente que algo no está claro.
¡Gracias!
2 Respuestas
4
Perdóname si me equivoco, pero creo que lo que intentas hacer es imposible (en el caso general), dadas las limitaciones que has mostrado en el ejemplo. En pocas palabras, ¿puede pensar en una forma de dibujar 71 puntos en un patrón hexagonal en una página con la misma altura y anchura que su ventana? No creo que exista tal patrón.
Para explicar más, considere la última línea en su código:
hexplot <- ppp(xcoords, ycoords, window=owin(c(0,MaxXValue),c(0,MaxYValue)))
Ahora, dado que su ventana tiene el mismo tamaño que los datos originales, para obtener la misma intensidad, necesitaría exactamente la misma cantidad de puntos (71). En su disposición hexagonal de puntos, tiene x filas, cada una de las cuales contiene y puntos. Pero no hay números enteros x e y que se multipliquen por 71.
Dicho esto, si "estiraste" un poco el ancho de la ventana, entonces la mitad de tus filas contendrían un punto más. Esa es una restricción un poco más flexible, pero no hay garantía de que en el caso general haya una solución.
Por lo tanto, para obtener exactamente la misma intensidad de punto, deberá poder cambiar el tamaño relativo de la ventana. Tendría que estirarlo para agregar un poco de espacio en blanco y obtener una intensidad de punto más baja. Eso todavía podría no funcionar en el caso general... pero podría, no lo he resuelto. Puede ser más fácil comenzar con una cuadrícula simple y luego expandir su código a hexágonos.
Mirando tu código, noté que estás usando while
bucles cuando podrías haber estado usando el seq
función. Por ejemplo, si desea generar todos los x
puntos de 0 a MaxXValue
aumentando en sqrt(3)*delta
, simplemente haz:
x<-seq(0,MaxXValue,by=delta)
en vez de tan grande while
. Puede haber algunos errores aquí, pero creo que podrías reducir todo tu código a:
library(spatstat)
data(swedishpines)
swedishpines.df <- as.data.frame(swedishpines)
MaxXValue <- max(swedishpines.df[1])
MaxYValue <- max(swedishpines.df[2])
NumberOfParticles <- nrow(swedishpines.df)
intensity <- NumberOfParticles / (MaxXValue*MaxYValue)
delta <- sqrt(2/(intensity*(sqrt(3))))
x<-seq(0,MaxXValue,by=delta)
y<-seq(0,MaxYValue,by=sqrt(3)*delta)
first.coords=merge(x,y) # Find every combo of x and y
x=seq(delta/2,MaxXValue,by=delta)
y=delta*sqrt(3)/2 + (delta*sqrt(3)*seq(0,length(x)/2))
second.coords=merge(x,y)
coords=rbind(first.coords,second.coords)
ppp(coords$x, coords$y, window=owin(c(0,MaxXValue),c(0,MaxYValue)))
Finalmente, noté en tus comentarios que mencionas que el área de un hexágono es ( sqrt(3) / 2 ) * delta^2
, pero no es (3*sqrt(3)/2) * delta^2
? `
Me interesó el comentario de Josh O'Brien y decidí implementar una función de rotación para obtener el número exacto de puntos deseado. Aquí está el código:
# Include all above code
rotate=function(deg) {
r=matrix(c(cos(deg),-sin(deg),sin(deg),cos(deg)),byrow=T,nrow=2)
rotated.coords=data.frame(t(r %*% t(as.matrix(coords))))
names(rotated.coords)=c('x','y')
rotated.coords
}
rotate.optim=function(deg) {
rotated.coords=rotate(deg)
abs(NumberOfParticles-length(suppressWarnings(ppp(rotated.coords$x, rotated.coords$y, window=owin(c(0,MaxXValue),c(0,MaxYValue)))$x)))
}
o=optim(0,rotate.optim,lower=0,upper=2*pi,method='Brent')
rotated.coords=rotate(o$par)
rotated.coords.window=rotated.coords[rotated.coords$x >= 0 & rotated.coords$y >= 0 & rotated.coords$x <= MaxXValue & rotated.coords$y <= MaxYValue,]
final=ppp(rotated.coords.window$x,rotated.coords.window$y,window=owin(c(0,MaxXValue),c(0,MaxYValue)))
plot(final)
Respondido 01 ago 12, 13:08
+1 para tu punto principal. Me parece que la única manera general de encajar n
apunta a un x
by y
sería rotar la cuadrícula ligeramente para que líneas enteras de puntos no entren en la ventana de visualización al mismo tiempo. - Josh O'Brien
¡Ni siquiera había considerado rotar la cuadrícula! Me pregunto si hay una prueba que demuestre que funcionaría en el caso general. - novas
Me alegro de que te haya gustado. No estoy seguro acerca de una prueba formal, pero parece que incluso con una cuadrícula orientada horizontalmente, siempre puede obtener la cantidad de puntos dentro de una línea de puntos del objetivo. Suponiendo que la línea inferior esté alineada con la parte inferior de la ventana, puede al menos: (1) desplazar la cuadrícula infinitesimalmente hacia arriba; (2) gírelo ligeramente; luego (3) mueva gradualmente la cuadrícula hacia abajo, eliminando un punto a la vez hasta que quede el número deseado. Hay "casos extremos" adicionales, pero esa sería una estrategia para una prueba. - Josh O'Brien
¡Esa es una solución absolutamente hermosa, nograpes! Su explicación inicial de por qué mi método anterior probablemente era imposible fue muy esclarecedora: era una corazonada que había tenido durante mucho tiempo, pero su interpretación fue mucho más coherente que la mía. La función de rotación también muy inteligente :) (¡Gracias a Josh O'Brien por la idea!). Muchas gracias por su tiempo y esfuerzo. Además, agregué una explicación en mis comentarios en referencia a la ecuación que usé para el área de un hexágono. - MikeZ
0
Solo para completar, agregaré que spatstat ahora tiene una función hexgrid
para generar una cuadrícula hexagonal, y hay rotate.ppp
que podría aplicarse después para rotar el patrón.
Respondido el 27 de enero de 15 a las 22:01
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas r while-loop ppp hexagonal-tiles spatstat or haz tu propia pregunta.
+1 por su pregunta bien construida e ilustrada. Podría valer la pena echarle un vistazo
hgridcent()
en el capítulo respecto a la hexágono paquete, aunque solo sea para comparar el código que usted y su autor usan para construir cuadrículas hexagonales. - Josh O'BrienNo he explorado esa caja de herramientas. Sin duda le echaré un vistazo, gracias. - MikeZ