QPix2 Part 2

The QPix software identifies a single region per plate (two regions total) and randomly picks a user defined number of colonies from each region. Ideally one would want to define 96 regions per plate so that the number of colonies per region can be specified - not allowed. However each colony’s location (X|Y deck coordinate) is recorded in an XML log file.

With a bit of hacking, the well location can be assigned to each colony. In this post I will process the XML log file to extract X|Y coordinates for each picked colony, associate those coordinates with wells, associate clone IDs with wells and ultimately associate the clone ID with a picked colony.

See this post for details concerning the input files and custom methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
rm(list=ls(all=TRUE))
library(XML)

setwd('~./qpix2')
#this is the files that indicates the clone IDs of the VH, VL fragments that
#have been cloned - the ID of the transformation mix
assoc.file <- "amplicon-plate-map.txt"
assoc <- read.table( paste(getwd(),"input", assoc.file, sep="/"), skip=0, header=TRUE)

> assoc
id dest.plate dest.well
1 PL101-VH amplicons A01
2 PL102-VH amplicons B01
3 PL103-VH amplicons C01
4 PL18-VH amplicons D01
5 PL28-VH amplicons E01
6 PL38-VH amplicons F01


##extract the runid as six integers
qpix.filename <- "QSoft Log 2014-02-11 105201.XML"
runid <- substring( qpix.filename, 22, 27)
> runid
[1] "105201"

Supply plate names of the plates in which the picked colonies were deposited. This is not needed if the plate names are typed directly into the software. For this example I will assume they are not. Enter as many destination plates as exist, the script will adjust

1
2
3
4

dest.plate <- list()
dest.plate[[1]] <- "PL140211c"
dest.plate[[2]] <- "PL140211d"

Use region 2 well H01 as the “origin”. Enter calibration block values for well G01. From G01 calculate H01 using hard coded offsets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

g01.x <- 114278
g01.y <- 241732
xstart <- g01.x + 2580
ystart <- g01.y - 8781
> xstart
[1] 116858
> ystart
[1] 232951

d <- xmlTreeParse( paste(getwd(), "/qpix-logs/", qpix.filename, sep="") )
top <- xmlRoot(d)
##top[[11]] has the "contents"; should be as many deposits as destination plates
>names(top[[11]])
routine imaging colonydata deposit deposit
"routine" "imaging" "colonydata" "deposit" "deposit"
>

Retrieve XML log files off the Qpix post run. Colony data is in //contents/colonydata. The XML can be easily visulaized by opening with a browser. Colonydata contains X|Y location as well as region. Read it in and create a dataframe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
colony.data <- getNodeSet(top, "//contents/colonydata")
d2 <- data.frame(t(sapply( xmlApply(colony.data[[1]], xmlAttrs),c)), stringsAsFactors=FALSE)
# region-image-colonyid uniquely identifies a colony
# not sure why image is needed
d2 <- d2[,c("colonyid","image","posx","posy","region")]

> head(d2)
colonyid image posx posy region
1 0 5 159286 385817 1
2 1 5 159569 403677 1
3 2 5 160654 385588 1
4 3 5 160761 388800 1
5 4 5 160854 371823 1
6 5 5 161284 390663 1
>

Calculate centers of each column along X axis.
Offset between regions 1 and 2 is 108174um.
The custom method getDeckWell defined here
Add the source well to the dataframe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

x.cent <- seq( xstart, by=9100, length.out=12)
yr1.cent <- seq( ystart+108174, by=9100, length.out=8)
yr2.cent <- seq( ystart, by=9100, length.out=8)

src.well <- rep( NA, nrow(d2))

for( i in 1:nrow(d2)){
src.well[i] <- getDeckWell( as.numeric(d2[ i, "posx"][[1]]), as.numeric(d2[ i, "posy"][[1]]), as.numeric(d2[ i, "region"][[1]]))
}
d2 <- cbind( d2, src.well)

> head(d2)
colonyid image posx posy region src.well
1 0 5 159286 385817 1 C06
2 1 5 159569 403677 1 A06
3 2 5 160654 385588 1 C06
4 3 5 160761 388800 1 C06
5 4 5 160854 371823 1 E06
6 5 5 161284 390663 1 C06
>

d2.wid <- merge( d2, assoc, by.x="src.well", by.y="dest.well")

> d2.wid
id colonyid src.well
1 PL101-VH 153 A01
2 PL101-VH 162 A01
3 PL101-VH 157 A01
4 PL101-VH 166 A01
5 PL101-VH 160 A01
6 PL44-VH 208 A02
7 PL44-VH 181 A02
8 PL44-VH 206 A02
9 PL44-VH 187 A02
10 PL44-VH 171 A02

Now we have associated an id based on well location to each colony.
src.well here is the well the clone came from in the transformation plate.
All we need here is colonyid assigned by Qpix and my clone id
src.well is the transformation well, keep that so you can
retrieve colonies that weren’t recovered by the Qpix.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

d2.wid <- d2.wid[,c("id","colonyid","src.well")]
deposit <-getNodeSet(top, "//contents/deposit")

deposit.list <- list()
for( i in 1: length(deposit)){
deposit.list[[i]] <- data.frame(t(sapply( xmlApply(deposit[[i]], xmlAttrs),c)), stringsAsFactors=FALSE)
}

#may not need to do this if destinations entered in software
for(i in 1:length(deposit.list)){
deposit.list[[i]]$destination <- dest.plate[[i]]
}

d3 <- do.call("rbind", deposit.list)


d3$location <- sapply( d3$location, insert0inWell)

> head(d3)
destination location colonyid source region
1 PL140211c A01 0 UIDUO0211-3912159-X 1
2 PL140211c B01 1 UIDUO0211-3912159-X 1
3 PL140211c C01 2 UIDUO0211-3912159-X 1
4 PL140211c D01 3 UIDUO0211-3912159-X 1
5 PL140211c E01 4 UIDUO0211-3912159-X 1
6 PL140211c F01 5 UIDUO0211-3912159-X 1

d4 <- merge(d3, d2.wid, by.x="colonyid", by.y="colonyid")
d4 <- d4[,c("destination","location","id","src.well")] #src.well is the transformation well
d4 <- d4[ order( d4$destination, d4$location),]
names(d4)[1:2] <- c("plate","well")
> head(d4)
plate well id src.well
1 PL140211c A01 PL78-VL C06
137 PL140211c A02 PL44-VL A06
51 PL140211c A03 PL86-VL C07
86 PL140211c A04 PL86-VL C07
95 PL140211c A05 PL95-VL D08
104 PL140211c A06 PL94-VL C08

results <- as.data.frame(table(d4$src.well))
results <- results[ order( results$Freq),]

> results
Var1 Freq
1 A01 0
15 C02 0
22 C09 0
26 D04 0
31 D09 0
40 E09 0
41 E10 0

Results shows the count of colonies obtained per clone ID. Some are not present in the collection, as can be seen above where Freq==0. This provides a list of wells that can be plated manually if these are considered valuable colonies.

Pick out 4 candidates (if available) for each clone ID.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
d5 <- do.call("rbind", lapply( split( d4, d4$bdn ), function(x) x[1:4,]) )
d5 <- d5[ !is.na(d5$bdn),]
d5 <- d5[ order( d5$plate, d5$well ),]

##evaluate
set1 <- read.table( paste(getwd(), "103410-picked-plates-map.txt", sep=""), skip=0, header=TRUE)
set2 <- read.table( paste(getwd(), "105201-picked-plates-map.txt", sep=""), skip=0, header=TRUE)

composite <- rbind(set1, set2)
out.file <-paste( working.dir, "composite.txt", sep="")
write.table( composite, file = out.file, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "NA", dec = ".", row.names = FALSE, col.names = TRUE, qmethod = c("escape", "double"))



results <- as.data.frame(table(composite$src.well))
results <- results[ order( results$Freq),]

plot(results)

set1 and set2 provide the plate maps for the picked plates.
results show the number of colonies picked for each candidate id. For those with 0-2 colonies, manually pick supplemental colonies if available.

results can be plotted to get a sense for the distribution of colony counts for the various candidate clones.

Share