I'm working to setup boundaries around 4 distinct regions of interest in an image - the image & data are in 0-1 normalized space, with four equally sized quadrants. It is easy to setup square boundaries:
df.all$ROI <- ifelse(df.all$x_pred_normalised > 0 & df.all$x_pred_normalised <= .5 &
df.all$y_pred_normalised > 0 & df.all$y_pred_normalised <= .5, c("lower_left"),
ifelse(df.all$x_pred_normalised > 0 & df.all$x_pred_normalised <= .5 &
df.all$y_pred_normalised > .5 & df.all$y_pred_normalised <= 1, c("upper_left"),
ifelse(df.all$x_pred_normalised > .5 & df.all$x_pred_normalised <= 1 &
df.all$y_pred_normalised > 0 & df.all$y_pred_normalised <= .5, c("lower_right"),
ifelse(df.all$x_pred_normalised > .5 & df.all$x_pred_normalised <= 1 &
df.all$y_pred_normalised > .5 & df.all$y_pred_normalised <= 1, c("upper_right"),
c("other")))))
However, I would like to setup a circular boundary (radius of.15 as an example) at the center of each quadrant (.25, .25; .25, .75; .75, .25; .75, .75) that provides the same output.
sample data:
x_pred_normalized <- rnorm(1000, mean=.5, sd=.5)
y_pred_normalized <- rnorm(1000, mean=.5, sd=.5)
df.all <- as.data.frame(cbind(x_pred_normalized, y_pred_normalized))
df.all$ROI_square <- ifelse(df.all$x_pred_normalised > 0 & df.all$x_pred_normalised <= .5 &
df.all$y_pred_normalised > 0 & df.all$y_pred_normalised <= .5, c("lower_left"),
ifelse(df.all$x_pred_normalised > 0 & df.all$x_pred_normalised <= .5 &
df.all$y_pred_normalised > .5 & df.all$y_pred_normalised <= 1, c("upper_left"),
ifelse(df.all$x_pred_normalised > .5 & df.all$x_pred_normalised <= 1 &
df.all$y_pred_normalised > 0 & df.all$y_pred_normalised <= .5, c("lower_right"),
ifelse(df.all$x_pred_normalised > .5 & df.all$x_pred_normalised <= 1 &
df.all$y_pred_normalised > .5 & df.all$y_pred_normalised <= 1, c("upper_right"),
c("other")))))
desired output:
x_pred_normalized y_pred_normalized ROI_square ROI_circle
.99 .99 upper_right other
.51 .51 upper_right other
.25 .25 lower_left lower_left
Your example does not result in data that you describe. AND your should NEVER use cbind
inside a call to data.frame
unless there's a dataframe object as one of the arguments. Here's a dataframe construction that does meet your description (and is small enough not to fill up your console with useless output when testing):
df.all <- data.frame(
x_pred_normalized = pmax( 0, pmin( rnorm(10, mean=.5, sd=.5), 0.99999)),
y_pred_normalized = pmax( 0, pmin( rnorm(10, mean=.5, sd=.5), 0.99999)) )
# all values between 0 and .99999
I find deeply nested ifelse
constructions very confusing to debug and wasteful of space, whereas using a two column matrix to select items from a character matrix to be easy to understand. The columns in the indexing numeric matrix are constructed with findInterval so it will be vectorized and much more efficient in both time and space.
df.all$quad <- matrix(c("First", "Third","Second","Fourth"), ncol=2)[ cbind(
findInterval(df.all$x_pred_normalized,c( 0, .5, 1,Inf) ),
findInterval(df.all$y_pred_normalized,c( 0, .5,1,Inf) ) )]
#--------------
> df.all
x_pred_normalized y_pred_normalized quad
1 0.78886879 0.3063979 Third
2 0.48122193 0.5440334 Second
3 0.85496224 0.4849327 Third
4 0.01457113 0.5116597 Second
5 0.76936612 0.7424495 Fourth
6 0.99999000 0.4544564 Third
7 0.55473184 0.0000000 Third
8 0.99967092 0.7843946 Fourth
9 0.72561140 0.3985747 Third
10 0.17755530 0.1337408 First
For the circle-containment column I would use a logical tests multiplied by an indexing value that could be used to extract a value from a vector via Boolean arithmetic:
dist= function(x,y)
df.all$circle <- with( df.all, c("other", "First", "Second", "Third", "Fourth")[
1 + # value when all subsequent tests are FALSE
1*(sqrt( (x_pred_normalized-0.25)^2+(y_pred_normalized-0.25)^2) <=0.25) +
# above should be should be 1 (TRUE) for lower-rt; else 0
2*(sqrt( (x_pred_normalized-0.25)^2+ (y_pred_normalized-0.75)^2) <=0.25)+
3*(sqrt( (x_pred_normalized-0.75)^2+(y_pred_normalized-0.25)^2) <=0.25)+
4*(sqrt( (x_pred_normalized-0.75)^2+(y_pred_normalized-0.75)^2)<=0.25) ] )
#--------------
> df.all
x_pred_normalized y_pred_normalized quad circle
1 0.78886879 0.3063979 Third Third
2 0.48122193 0.5440334 Second other
3 0.85496224 0.4849327 Third other
4 0.01457113 0.5116597 Second other
5 0.76936612 0.7424495 Fourth Fourth
6 0.99999000 0.4544564 Third other
7 0.55473184 0.0000000 Third other
8 0.99967092 0.7843946 Fourth other
9 0.72561140 0.3985747 Third Third
10 0.17755530 0.1337408 First First
I see that I used a circular radius of 0.25 whereas you asked for 0.15. The necessary changes should be easy to implement.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.