循环浏览文件,获取theta并按R中的theta旋转曲线 [英] Loop through files, obtain theta and rotate curve by theta in R

查看:51
本文介绍了循环浏览文件,获取theta并按R中的theta旋转曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问了一个问题

I asked a question here where Miff helped me figure out how to find the point on a curve which is perpendicular to the line between the endpoints at its midpoint.

To do this, the user pointed out it was necessary to rotate the curve by the gradient of the line joining the endpoints so that the line is flat, using approx, and then rotate in the opposite direction using the lava package. I can make this work on a case by case basis, establishing theta and working from there. I'm having really bad luck trying to embed this within a function, however.

I am having difficulty using dplyr to rotate each set of 42 points by a theta value within a function.

Here's a sample set of data. The real data has hundreds of curves I need to work through.

data <- structure(list(X = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 4.9046, 
6.1424, 7.275, 8.5851, 10.0373, 11.9981, 13.7726, 15.0731, 16.0664, 
18.1945, 21.2666, 24.2093, 26.7119, 28.8037, 30.7135, 32.1351, 
33.1982, 34.2341, 35.7587, 37.2147, 38.4303, 39.625, 40.4596, 
42.0938, 42.7428, 42.7593, 43.5085, 43.7419, 43.5989, 44.0841, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -14.845, -11.9052, 
-8.7897, -5.8034, -2.6756, 0.3316, 3.4003, 6.5281, 9.6517, 12.804, 
15.9861, 19.1769, 22.2929, 25.4089, 28.3392, 31.0054, 33.1847, 
35.081, 36.7227, 38.1544, 39.1697, 40.049, 40.9647, 41.5014, 
41.8874, 42.1778, 42.3435, 42.2681, 42.3745, 42.4619, NA, NA, 
NA, NA), Y = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, -9.9938, -7.4596, 
-4.8647, -2.2903, 0.3158, 2.9302, 5.7262, 8.7033, 11.8007, 14.9847, 
16.7225, 16.7813, 15.6921, 14.2964, 11.5579, 8.2378, 5.183, 1.5938, 
-2.0712, -5.195, -7.1447, -9.0446, -11.1269, -13.0979, -15.3295, 
-17.1898, -19.4376, -21.4781, -23.8426, -25.6343, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, 8.0113, 9.1826, 9.838, 10.7908, 
11.175, 12.0393, 12.6813, 12.8828, 13.2281, 13.5102, 13.6637, 
13.5493, 12.8699, 12.2191, 10.9208, 9.0209, 6.2158, 3.2466, 0.2169, 
-2.7807, -6.0439, -9.1262, -11.8684, -14.7779, -17.5825, -20.2452, 
-22.807, -25.3519, -27.6105, -29.7536, NA, NA, NA, NA), fan_line = c(1L, 
2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 
16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 
29L, 30L, 31L, 32L, 33L, 34L, 35L, 36L, 37L, 38L, 39L, 40L, 41L, 
42L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 
14L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 
27L, 28L, 29L, 30L, 31L, 32L, 33L, 34L, 35L, 36L, 37L, 38L, 39L, 
40L, 41L, 42L)), class = "data.frame", row.names = c(NA, -84L
))

Currently within the function, I loop through each set of 42 XY coordinates that constitute my curves of interest, and obtain the start and end XY coordinates for each curve:

plyr, dplyr, tidyr and lava are loaded

data <- data %>% mutate(Group = rep(1:(n()/42), each = 42)) %>% dplyr::group_by(Group) %>% 
    mutate(start = min(which(!is.na(X))), end = max(which(!is.na(X))), midpoint = round((start+end)/2, digits = 0)) %>% ungroup()

for (i in 1:nrow(data)){
    if (data[i, "fan_line"] == data[i, "start"]){
      data[i, "start_val_x"] = data[i, "X"]
      data[i, "start_val_y"] = data[i, "Y"]
    }
    else{data[i, "start_val_y"] = NA
    data[i, "start_val_x"] = NA}
  }
  
  for (i in 1:nrow(data)){
    if (data[i, "fan_line"] == data[i, "end"]){
      data[i, "end_val_x"] = data[i, "X"]
      data[i, "end_val_y"] = data[i, "Y"]
    }
    else{data[i, "end_val_y"] = NA
    data[i, "end_val_x"] = NA}
  }

data <- data %>%  group_by(Group) %>% fill(c(start_val_x, start_val_y), .direction = "down") %>% fill(c(start_val_x, start_val_y), .direction = "up")
data2 <- data %>%  group_by(Group) %>% fill(c(end_val_x, end_val_y), .direction = "down") %>% fill(c(end_val_x, end_val_y), .direction = "up")

Here I find points along a line running between the start and endpoints along each curve. In this cases, it is the one third point.

data3 <- data2 %>% group_by(Group) %>% mutate(x_value_one_third_hypo = ((start_val_x/3)*2 + (end_val_x*0.33)),
                                            y_value_one_third_hypo = ((start_val_y/3)*2 + (end_val_y*0.33)),
                                            third_x = approx(X, Y, (min(X, na.rm = T)/3)*2 + (max(X, na.rm = T)/3))$x,
                                            third_y = approx(X, Y, (min(X, na.rm = T)/3)*2 + (max(X, na.rm = T)/3))$y)

I calculate theta for each curve like so:

data3 <- data3 %>% group_by(Group) %>% mutate(theta = max(atan(diff(c(start_val_y, end_val_y))/diff(c(start_val_x, end_val_x))), na.rm = T))

However, I then run into the problem of trying to rotate using this theta value - I get an error message informing me that object theta is not found.

  data3.5 <- data3 %>% bind_cols(as_tibble(rotate2(as.matrix(.)[,1:2], theta = theta)))

I'm not sure how I can rotate the coordinates of each set of xy coordinates by their corresponding theta values.

解决方案

I'm sure there's an easier way to do this, but it works. That's assuming that you're trying to rotate about the origin. If you wanted to use an arbitrary axis, this won't be right.

I did have to change the data to work through this because there is no 80 to match to end, so I changed it to 38 just to work through the code.

I thought that the lava function required a square matrix, but that didn't work, so I went back to the more traditional rotation matrix.

Using the theta you calculated, I created this matrix in R

# create the 2D rotation matrix
tMat = rbind(c(cos(unique(data3$theta)), 
               -1* sin(unique(data3$theta))),
             c(sin(unique(data3$theta)), 
               cos(unique(data3$theta))))

# an empty list to store the results
trXY <- vector("list")   # transformed xy storage

# transform points - extract x & y, put into a vector, then matrix mult
for(i in 1:nrow(data3)){
  # collect original x and y
  coordData = data3[i, 1:2] %>% unlist()
 
  # skip the NA rows
  if(is.na(data3[i, 1]) == F) {
     # calculate
     results <- tMat %*% coordData
     # store the results
     trXY[i] <- list(results)
   } # end if
   else{
     # is NA
     trXY[i] <- NA
   } # end else
 } # end for

 # check output
 trXY[38] # it's stored in rows x is row 1; y is row 2

 # extract coordinates from the list and put them in the data frame
 # x coord
 data3$trX <- apply(trXY, function(x) ifelse(length(x) == 1,
                                             NA,
                                             x[[1]])) %>% unlist()
 # y coord
 data3$trY <- apply(trXY, function(x) ifelse(length(x) == 1,
                                             NA,
                                             x[[2]])) %>% unlist()

  # check rotation
  (p <- plotly::plot_ly(data3, 
                        x = ~X, 
                        y = ~Y, 
                        name = "original data", 
                        type = "scatter", 
                        mode = "lines", 
                        color = ~Group %>% as.factor(), 
                        colors = c("#cd0c18","#1660a7")) %>% 
     plotly::add_trace(x = ~trX, 
                       y = ~trY, 
                       name = "transformed", 
                       mode = "lines", 
                       color = ~Group %>% as.factor(), 
                       line = list(dash = "dash")))

This is what it looks like:

这篇关于循环浏览文件,获取theta并按R中的theta旋转曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆