Reputation: 13
I have a dataframe data
with several columns including ID Image
(repeated for several rows) and X CenterX_um
and Y CenterY_um
coordinate (different for each row).
I want to rotate the X, Y coordinates based on an angle and origin that are specific for each ID. I also have this info on a separate dataframe rotation_info
.
I have tried the rearrr::rotate_2d
function but it doesn't let me specify the angle and origin. Rather, it wants to use the same angle and origin for all.
Any clues?
Here is a subset of each dataframe:
data <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
"P112_SOD1_scene-03_roi1", "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-08_roi1", "P112_SOD1_scene-08_roi1",
"P112_SOD1_scene-14_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1", "P112_WT_scene-13_roi1"),
Area_pixel2 = c(6172L, 2804L, 4133L, 1547L, 9224L, 5133L, 4311L, 2740L, 2610L, 3802L, 5129L, 4106L),
Area_um2 = c(318.03702442715, 144.48733254921, 212.96938139297, 79.715372130394, 475.30355044005, 264.49838729497, 222.14154444352,
141.18947617148, 134.49070540422, 195.91328043941, 264.29227127136, 211.57809823361),
CenterX_um = c(1149.8904493589, 1126.4609300602, 1100.8211294593, 1024.1176019595, 993.32875148771, 964.51498442025, 874.9485394368,
843.03397382692, 1457.7886911485, 1359.4372824824, 1549.4154976822, 1614.8843949665),
CenterY_um = c(65.734010569428, 87.806098466489, 121.24362888879, 344.12182158201, 349.1125830895, 378.36327230154, 222.10103046474,
236.8534704986, 524.97197144378, 536.26329031132, 101.93303030628, 103.3766130805),
Circularity = c(0.70514719268137, 0.73725777209061, 0.55904614141807, 0.64491724919754, 0.72628772170604, 0.68836548793912,
0.80455000787307, 0.75794971514553, 0.58945714820048, 0.75891540252167, 0.63520099709918, 0.79151119246911),
Compactness = c(0.66065335617958, 0.64189735971181, 0.53383026406418, 0.53076228622962, 0.76004630952984, 0.72584335956662,
0.81606076244974, 0.77264654886067, 0.51250290104024, 0.78515382913133, 0.66035724052464, 0.80977712999347)),
row.names = c(1L, 2L, 3L, 1505L, 1506L, 1507L, 8500L, 8501L, 15689L, 15690L, 30001L, 30002L), class = "data.frame")
data
# Image Area_pixel2 Area_um2 CenterX_um CenterY_um Circularity Compactness
#1 P112_SOD1_scene-01_roi1 6172 318.03702 1149.8904 65.73401 0.7051472 0.6606534
#2 P112_SOD1_scene-01_roi1 2804 144.48733 1126.4609 87.80610 0.7372578 0.6418974
#3 P112_SOD1_scene-01_roi1 4133 212.96938 1100.8211 121.24363 0.5590461 0.5338303
#1505 P112_SOD1_scene-03_roi1 1547 79.71537 1024.1176 344.12182 0.6449172 0.5307623
#1506 P112_SOD1_scene-03_roi1 9224 475.30355 993.3288 349.11258 0.7262877 0.7600463
#1507 P112_SOD1_scene-03_roi1 5133 264.49839 964.5150 378.36327 0.6883655 0.7258434
#8500 P112_SOD1_scene-08_roi1 4311 222.14154 874.9485 222.10103 0.8045500 0.8160608
#8501 P112_SOD1_scene-08_roi1 2740 141.18948 843.0340 236.85347 0.7579497 0.7726465
#15689 P112_SOD1_scene-14_roi1 2610 134.49071 1457.7887 524.97197 0.5894571 0.5125029
#15690 P112_SOD1_scene-14_roi1 3802 195.91328 1359.4373 536.26329 0.7589154 0.7851538
#30001 P112_WT_scene-13_roi1 5129 264.29227 1549.4155 101.93303 0.6352010 0.6603572
#30002 P112_WT_scene-13_roi1 4106 211.57810 1614.8844 103.37661 0.7915112 0.8097771
rotation_info <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
"P112_SOD1_scene-08_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1"
), Angle = c(199.289658091447, 202.184697711029, 158.990932730799,
180.612494033135, 15.223442470483), CC_X = c(989.039056641, 970.652055588,
1104.355063245, 781.334044746, 1034.893059267), CC_Y = c(792.457045383,
798.359045721, 940.915053885, 747.057042783, 709.829040651)), row.names = c(NA,
-5L), class = "data.frame")
rotation_info
# Image Angle CC_X CC_Y
#1 P112_SOD1_scene-01_roi1 199.28966 989.0391 792.4570
#2 P112_SOD1_scene-03_roi1 202.18470 970.6521 798.3590
#3 P112_SOD1_scene-08_roi1 158.99093 1104.3551 940.9151
#4 P112_SOD1_scene-14_roi1 180.61249 781.3340 747.0570
#5 P112_WT_scene-13_roi1 15.22344 1034.8931 709.8290
My idea was to first merge both dataframes based on Image
so that the angle and origin would be duplicated for each row (this works well), and then apply the rearrr::rotate_2d
function to each row. This is when I run into trouble because it wants the same angle and origin for all rows.
# Merge rotation info into data
data <- merge(data, rotation_info, by="Image", all.x=TRUE)
# Rotate based on angle ("Angle") and origin ("CC_X", "CC_Y")
data <- rotate_2d(data, degrees = data$Angle, x_col = "CenterX_um", y_col = "CenterY_um",
origin = c(data$CC_X, data$CC_Y) , suffix = "", overwrite = TRUE)
Any other approach is welcome. I don't necessarily need the rotation info in my dataframe (I was planning to drop it after, actually).
Thanks in advance!
Upvotes: 1
Views: 790
Reputation: 5254
It seems that rearrr::rotate_2d()
is not really designed to take in degrees
and origin
arguments from the source data in the way that you're trying to. If done this way it will rotate every point by every Angle
around every origin
.
Instead I used purrr::group_map()
to split the data by Image
and separately operate on each with a single degrees
and origin
argument (collapsed by mean(., na.rm = T)
although you could use unique()
or min()
or anything else to get a single value instead of a vector of repeated values).
See plot at bottom where I show original and rotated points in red and blue respectively and the origin for each with the *.
library(tidyverse)
library(rearrr)
data <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
"P112_SOD1_scene-03_roi1", "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-08_roi1", "P112_SOD1_scene-08_roi1",
"P112_SOD1_scene-14_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1", "P112_WT_scene-13_roi1"),
Area_pixel2 = c(6172L, 2804L, 4133L, 1547L, 9224L, 5133L, 4311L, 2740L, 2610L, 3802L, 5129L, 4106L),
Area_um2 = c(318.03702442715, 144.48733254921, 212.96938139297, 79.715372130394, 475.30355044005, 264.49838729497, 222.14154444352,
141.18947617148, 134.49070540422, 195.91328043941, 264.29227127136, 211.57809823361),
CenterX_um = c(1149.8904493589, 1126.4609300602, 1100.8211294593, 1024.1176019595, 993.32875148771, 964.51498442025, 874.9485394368,
843.03397382692, 1457.7886911485, 1359.4372824824, 1549.4154976822, 1614.8843949665),
CenterY_um = c(65.734010569428, 87.806098466489, 121.24362888879, 344.12182158201, 349.1125830895, 378.36327230154, 222.10103046474,
236.8534704986, 524.97197144378, 536.26329031132, 101.93303030628, 103.3766130805),
Circularity = c(0.70514719268137, 0.73725777209061, 0.55904614141807, 0.64491724919754, 0.72628772170604, 0.68836548793912,
0.80455000787307, 0.75794971514553, 0.58945714820048, 0.75891540252167, 0.63520099709918, 0.79151119246911),
Compactness = c(0.66065335617958, 0.64189735971181, 0.53383026406418, 0.53076228622962, 0.76004630952984, 0.72584335956662,
0.81606076244974, 0.77264654886067, 0.51250290104024, 0.78515382913133, 0.66035724052464, 0.80977712999347)),
row.names = c(1L, 2L, 3L, 1505L, 1506L, 1507L, 8500L, 8501L, 15689L, 15690L, 30001L, 30002L), class = "data.frame")
rotation_info <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
"P112_SOD1_scene-08_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1"),
Angle = c(199.289658091447, 202.184697711029, 158.990932730799, 180.612494033135, 15.223442470483),
CC_X = c(989.039056641, 970.652055588, 1104.355063245, 781.334044746, 1034.893059267),
CC_Y = c(792.457045383, 798.359045721, 940.915053885, 747.057042783, 709.829040651)),
row.names = c(NA, -5L), class = "data.frame")
# Merge rotation info into data
data2 <- merge(data, rotation_info, by="Image", all.x=TRUE)
# rotate each image by its respective origin and angle
data3 <- data2 %>%
group_by(Image) %>%
group_map(
~ rotate_2d(
data = .,
degrees = mean(.[["Angle"]], na.rm = T),
x_col = "CenterX_um",
y_col = "CenterY_um",
origin = c(mean(.[["CC_X"]], na.rm = T), mean(.[["CC_Y"]], na.rm = T)),
keep_original = TRUE
),
.keep = T
) %>%
bind_rows()
# visualize rotated result vs original
data3 %>%
select(Image, CC_X:CC_Y, starts_with("Center")) %>%
group_by(Image) %>%
mutate(point_id = row_number()) %>%
ungroup() %>%
pivot_longer(
cols = -c(Image, point_id, CC_X, CC_Y),
names_to = c("axis", "units", "rotation"),
names_prefix = "Center",
names_sep = "_",
values_to = "position"
) %>%
replace_na(list(rotation = "original")) %>%
pivot_wider(names_from = axis, values_from = position) %>%
ggplot(aes(X, Y, color = rotation)) +
geom_point() +
geom_path() +
geom_point(aes(CC_X, CC_Y), size = 4, color = "black", shape = 8) +
facet_wrap(~Image, scales = "free")
#> Warning: Expected 3 pieces. Missing pieces filled with `NA` in 2 rows [1, 2].
Created on 2022-01-27 by the reprex package (v2.0.1)
Upvotes: 2