bioanalyzeR

Joe Foley

2022-06-10

Introduction

This package imports data from Agilent automated electrophoresis systems (Bioanalyzer, TapeStation, Fragment Analyzer, ZAG DNA Analyzer, Femto Pulse) and includes functions to graph and analyze the data. To download or contribute to the package, please see its page on GitHub.

Features

Why is this useful?

Exporting data from the Agilent software

Bioanalyzer

In the 2100 Expert software, open your data file (.xad) in the “Data” context. Select “File->Export…” from the top menu. Check the “Export to XML” box and no others. Click “Export” and then save the file wherever you like.

TapeStation

Exporting TapeStation data requires version 4.1 or higher of the TapeStation Analysis software. Open your data file (.D1000, .HSD1000, .RNA., .gDNA, etc.). You need to export both the metadata (in XML format) and electropherogram data (CSV), so you will generate two similarly named output files from each input file.

Metadata XML

Select “File->Export Data->Export to XML”. You do not need to export the gel image or individual EPG images. Select your destination and then click “Export” to save the file.

Electropherogram CSV

Select “File->Export Data->Export to CSV”. Unselect all files except “Electropherogram Data”, and unselect “Aligned”. The other settings do not matter but the filename must match the XML file. The software will append _Electropherogram.csv to the name you enter.

ProSize (Fragment Analyzer, ZAG DNA Analyzer, Femto Pulse)

The data must be exported with a specific configuration. Unfortunately this precludes the use of Batch Processing mode.

  1. Open your file and verify there are no problems.
  2. Verify that the marker peaks are shown in the lower right peak table. If not, click the tool icon above the peak table, then in “Advanced Settings” fill the circle for “Show Marker Information on Peak Table”.
  3. In the top-left “File” menu select “Export Data”.
  4. Click the gear icon next to “Peak Table” to configure the peak table.
  5. Verify that all of these fields are present; order is not important (you can save this configuration as a “custom pattern”):
    • size, e.g. “Size (bp)”
    • “% (Conc.)”
    • molarity, e.g. “nmole/L”
    • concentration, e.g. “ng/ul”
    • lower boundary, e.g. “From (bp)”
    • upper boundary, e.g. “To (bp)”
  6. Click “Apply” to use this configuration for the peak table.
  7. Fill the circles to export the “Alternate” peak table format.
  8. Fill the circles to export the “Smear Analysis Table” and “Quality Table” if applicable.
  9. Fill the circles to export the “Electropherogram” as a “Single File”.
  10. Fill the circle to set the “X Axis Scale Option” to “Time Scale”.
  11. Fill the circle to export the “Size Calibration Data”.
  12. It is not necessary to export the quality table or gel, or set the image format.
  13. Set the desired “Export File Path”.
  14. When all the settings are correct, click “Export”.
  15. (Optional) When the “Export Complete” window pops up, click “Open Folder Now” to verify all of these files are present:
    • electropherogram (... Electropherogram.csv)
    • peak table (... Peak Table.csv)
    • size calibration (... Size Calibration.csv)
    • smear analysis, if applicable (... Smear Analysis Result.csv)
    • quality table, if applicable (... Quality Table.csv)
  16. (Optional) If you exported into the same directory as the open data file, from the “Help” menu in the upper right select “Zip Opened Data File” to create a ZIP archive containing all the data files. Alternatively, use other software to put the exported CSV files into a ZIP archive. This is more portable than loose CSV files and you can set the batch name by renaming the ZIP file.

To be imported, the required CSV files must be together in the same directory or ZIP archive with the original filenames generated by the ProSize software. Only the CSV files are required.

Data storage and transfer

This package can read XML files compressed with gzip. Although the Agilent software does not automatically compress its exported XML files, it may be helpful to compress them yourself for long-term storage, particularly the large Bioanalyzer XML files that contain all the raw data.

Uncompressed XML files are assumed to have the extension .xml and compressed ones .xml.gz. TapeStation gel image files are assumed to have the extension .png.

The filename you import can be a local path or a URL, so in principle you can directly open data stored on a remote server. However, opening from URLs works with some servers and fails with others because of problems with file handling in the XML package, which are outside the scope of this package to fix.

Importing data

This package includes the read.bioanalyzer, read.tapestation, and read.prosize functions to import data from the different platforms, but it is easier to use the wrapper function read.electrophoresis, which automatically determines the type of data and can read multiple files into a single object.

Demo data included in this package

For a demonstration, we can use some pre-exported example data from the Agilent software. This package’s extdata subdirectory contains the pre-exported data from every supported demo file included with the Bioanalyzer 2100 Expert and TapeStation Analysis software (with some typos in the sample names corrected so they are easy to parse):

find.package("bioanalyzeR")
#> [1] "/tmp/Rtmp3ed50Y/temp_libpath402f76dfb8b2/bioanalyzeR"
list.files(paste0(find.package("bioanalyzeR"), "/extdata"), recursive = TRUE)
#>  [1] "bioanalyzer/Demo DNA 1000 Series II.xml.gz"                                                                        
#>  [2] "bioanalyzer/Demo DNA 12000 Series II.xml.gz"                                                                       
#>  [3] "bioanalyzer/Demo DNA 7500 Series II.xml.gz"                                                                        
#>  [4] "bioanalyzer/Demo Eukaryote Total RNA Nano Series II.xml.gz"                                                        
#>  [5] "bioanalyzer/Demo Eukaryote Total RNA Pico Series II.xml.gz"                                                        
#>  [6] "bioanalyzer/Demo High Sensitivity DNA.xml.gz"                                                                      
#>  [7] "bioanalyzer/Demo mRNA Nano Series II.xml.gz"                                                                       
#>  [8] "bioanalyzer/Demo mRNA Pico Series II.xml.gz"                                                                       
#>  [9] "bioanalyzer/Demo Plant RNA Nano.xml.gz"                                                                            
#> [10] "bioanalyzer/Demo Plant RNA Pico.xml.gz"                                                                            
#> [11] "bioanalyzer/Demo Prokaryote Total RNA Nano Series II.xml.gz"                                                       
#> [12] "bioanalyzer/Demo Prokaryote Total RNA Pico Series II.xml.gz"                                                       
#> [13] "femtopulse/FP-1002 gDNA 165 kb/Yeast Extractions 165Kb EXT F12102 12-41-55.zip"                                    
#> [14] "femtopulse/FP-1002 gDNA 165 kb/Yeast Extractions 165Kb Fast F12102 17-27-23.zip"                                   
#> [15] "femtopulse/FP-1003 55 Kb BAC/17-54-18.zip"                                                                         
#> [16] "femtopulse/FP-1101 US NGS/300 bp dilution series 21-30-31.zip"                                                     
#> [17] "femtopulse/FP-1101 US NGS/Smear dilution 15-49-01.zip"                                                             
#> [18] "femtopulse/FP-1201 US RNA/FP-1201 Mouse mRNA Dilution Series.zip"                                                  
#> [19] "femtopulse/FP-1201 US RNA/FP-1201 Univeral Mouse Ref Total RNA Dilution Series.zip"                                
#> [20] "fragmentanalyzer/DNF-464 HS Large Fragment/Long read library final QC 18-12-47.zip"                                
#> [21] "fragmentanalyzer/DNF-467 Genomic 50 kb/16-30-38.zip"                                                               
#> [22] "fragmentanalyzer/DNF-467 Genomic 50 kb/21-54-28.zip"                                                               
#> [23] "fragmentanalyzer/DNF-468 HS Genomic 50 kb/Human gDNA 38 15-0.2 ng series DNF-468 kit 12Cap 33cm Array 12-26-43.zip"
#> [24] "fragmentanalyzer/DNF-470 Small RNA/17-44-37.zip"                                                                   
#> [25] "fragmentanalyzer/DNF-471 RNA kit 15nt/DNF-471-33 E. coli Total RNA Dilution Series 12-22-09.zip"                   
#> [26] "fragmentanalyzer/DNF-472 HS RNA kit 15nt/DNF-472M Mouse & Rat mRNA dilutions.zip"                                  
#> [27] "fragmentanalyzer/DNF-472 HS RNA kit 15nt/RNA Degradation Study 12-03-13.zip"                                       
#> [28] "fragmentanalyzer/DNF-472 HS RNA kit 15nt/sample dilution series 20-07-57.zip"                                      
#> [29] "fragmentanalyzer/DNF-473 NGS Fragment kit (1-6000)/NGS Libraries SS NGS kit 19-10-40.zip"                          
#> [30] "fragmentanalyzer/DNF-474 HS NGS (1-6000)/DNA smear dilution series 10-39-02.zip"                                   
#> [31] "fragmentanalyzer/DNF-474 HS NGS (1-6000)/Final NGS library QC 11-32-01.zip"                                        
#> [32] "fragmentanalyzer/DNF-474 HS NGS (1-6000)/SureSelect library with primer dimer 16-38-33.zip"                        
#> [33] "fragmentanalyzer/DNF-476 Small Fragment (1-1500)/DNF-476 SS Small Fragment Kit sRNA Lib Demo Data 17-23-42.zip"    
#> [34] "fragmentanalyzer/DNF-477 HS Small Fragment (1-1500)/cfDNA 15-22-09.zip"                                            
#> [35] "fragmentanalyzer/DNF-477 HS Small Fragment (1-1500)/Small DNA smear 19-18-22.zip"                                  
#> [36] "fragmentanalyzer/DNF-910CP CRISPR Gel Discovery/2017 02 08 12H 18M.zip"                                            
#> [37] "fragmentanalyzer/DNF-915 dsDNA (35-5000)/Arabidopsis genotyping 16-33-12.zip"                                      
#> [38] "fragmentanalyzer/DNF-920 dsDNA (75-15000)/10-34-17.zip"                                                            
#> [39] "fragmentanalyzer/DNF-930 dsDNA (35-5000)/14-58-36.zip"                                                             
#> [40] "tapestation/cfDNA-Plate-96-cfDNA_Electropherogram.csv.gz"                                                          
#> [41] "tapestation/cfDNA-Plate-96-cfDNA.xml.gz"                                                                           
#> [42] "tapestation/cfDNA-Tubes-16-cfDNA_Electropherogram.csv.gz"                                                          
#> [43] "tapestation/cfDNA-Tubes-16-cfDNA.xml.gz"                                                                           
#> [44] "tapestation/D1000-Plate-96-D1000_Electropherogram.csv.gz"                                                          
#> [45] "tapestation/D1000-Plate-96-D1000.xml.gz"                                                                           
#> [46] "tapestation/D1000-Plate-96.annotations.csv"                                                                        
#> [47] "tapestation/D1000-Tubes-16-D1000_Electropherogram.csv.gz"                                                          
#> [48] "tapestation/D1000-Tubes-16-D1000.xml.gz"                                                                           
#> [49] "tapestation/D5000-Plate-96-D5000_Electropherogram.csv.gz"                                                          
#> [50] "tapestation/D5000-Plate-96-D5000.xml.gz"                                                                           
#> [51] "tapestation/D5000-Tubes-16-D5000_Electropherogram.csv.gz"                                                          
#> [52] "tapestation/D5000-Tubes-16-D5000.xml.gz"                                                                           
#> [53] "tapestation/Eukaryotic RNA-Plate-64-RNA_Electropherogram.csv.gz"                                                   
#> [54] "tapestation/Eukaryotic RNA-Plate-64-RNA.xml.gz"                                                                    
#> [55] "tapestation/Eukaryotic RNA-Tubes-16-RNA_Electropherogram.csv.gz"                                                   
#> [56] "tapestation/Eukaryotic RNA-Tubes-16-RNA.xml.gz"                                                                    
#> [57] "tapestation/gDNA-Plate-96-gDNA_Electropherogram.csv.gz"                                                            
#> [58] "tapestation/gDNA-Plate-96-gDNA.xml.gz"                                                                             
#> [59] "tapestation/gDNA-Tubes-16-gDNA_Electropherogram.csv.gz"                                                            
#> [60] "tapestation/gDNA-Tubes-16-gDNA.xml.gz"                                                                             
#> [61] "tapestation/High Sensitivity D1000-Tubes-16-HSD1000_Electropherogram.csv.gz"                                       
#> [62] "tapestation/High Sensitivity D1000-Tubes-16-HSD1000.xml.gz"                                                        
#> [63] "tapestation/High Sensitivity D5000-Tubes-16-HSD5000_Electropherogram.csv.gz"                                       
#> [64] "tapestation/High Sensitivity D5000-Tubes-16-HSD5000.xml.gz"                                                        
#> [65] "tapestation/High Sensitivity Eukaryotic RNA-Plate-96-HSRNA_Electropherogram.csv.gz"                                
#> [66] "tapestation/High Sensitivity Eukaryotic RNA-Plate-96-HSRNA.xml.gz"                                                 
#> [67] "tapestation/High Sensitivity Eukaryotic RNA-Tubes-16-HSRNA_Electropherogram.csv.gz"                                
#> [68] "tapestation/High Sensitivity Eukaryotic RNA-Tubes-16-HSRNA.xml.gz"                                                 
#> [69] "tapestation/HSD1000-HaloplexHS-4-HSD1000_Electropherogram.csv.gz"                                                  
#> [70] "tapestation/HSD1000-HaloplexHS-4-HSD1000.xml.gz"                                                                   
#> [71] "tapestation/HSD5000-SureSelectQXT-3-HSD5000_Electropherogram.csv.gz"                                               
#> [72] "tapestation/HSD5000-SureSelectQXT-3-HSD5000.xml.gz"                                                                
#> [73] "tapestation/Prokaryotic RNA-Plate-32-RNA_Electropherogram.csv.gz"                                                  
#> [74] "tapestation/Prokaryotic RNA-Plate-32-RNA.xml.gz"                                                                   
#> [75] "zag/ZAG-105 dsDNA (1-500)/10-23-09.zip"                                                                            
#> [76] "zag/ZAG-105 dsDNA (1-500)/11-34-22.zip"                                                                            
#> [77] "zag/ZAG-110 dsDNA (35-5000)/10-25-24.zip"                                                                          
#> [78] "zag/ZAG-130 dsDNA (75-20000)/ZAG-130 GP 20-53-59.zip"                                                              
#> [79] "zag/ZAG-135 dsDNA (1-1500)/09-45-24.zip"

So let’s import a file and see what we have:

dna1000 <- read.electrophoresis(system.file(
    "extdata",
    "bioanalyzer",
    "Demo DNA 1000 Series II.xml.gz",
    package = "bioanalyzeR"
))
dna1000$assay.info
#> $`Demo DNA 1000 Series II`
#> $`Demo DNA 1000 Series II`$file.name
#> [1] "C:\\Program Files (x86)\\Agilent\\2100 bioanalyzer\\2100 expert\\data\\samples\\demo\\electrophoresis\\Demo DNA 1000 Series II.xad"
#> 
#> $`Demo DNA 1000 Series II`$creation.date
#> [1] "2005-12-14T08:03:40.000"
#> 
#> $`Demo DNA 1000 Series II`$assay.name
#> [1] "DNA 1000 Series II"
#> 
#> $`Demo DNA 1000 Series II`$assay.type
#> [1] "DNA"
#> 
#> $`Demo DNA 1000 Series II`$length.unit
#> [1] "bp"
#> 
#> $`Demo DNA 1000 Series II`$concentration.unit
#> [1] "ng/µl"
#> 
#> $`Demo DNA 1000 Series II`$molarity.unit
#> [1] "nM"
#> 
#> $`Demo DNA 1000 Series II`$method
#> [1] "hyman"
dna1000$samples
batch well.number sample.name sample.observations sample.comment ladder.well
Demo DNA 1000 Series II 1 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 2 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 3 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 4 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 5 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 6 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 7 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 8 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 9 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 10 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 11 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 12 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 13 Ladder Ladder DNA 1000 13

Or we can read several files into one object:

several.files <- read.electrophoresis(
    system.file(
        "extdata",
        "bioanalyzer",
        "Demo DNA 1000 Series II.xml.gz",
        package = "bioanalyzeR"
    ),
    system.file(
        "extdata",
        "bioanalyzer",
        "Demo DNA 7500 Series II.xml.gz",
        package = "bioanalyzeR"
    ),
    system.file(
        "extdata",
        "bioanalyzer",
        "Demo DNA 12000 Series II.xml.gz",
        package = "bioanalyzeR"
    )
)
several.files$samples
batch well.number sample.name sample.observations sample.comment ladder.well
Demo DNA 1000 Series II 1 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 2 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 3 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 4 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 5 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 6 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 7 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 8 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 9 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 10 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 11 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 12 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 13 Ladder Ladder DNA 1000 13
Demo DNA 7500 Series II 1 ladder 1 Ladder 1 13
Demo DNA 7500 Series II 2 ladder 2 Ladder 2 13
Demo DNA 7500 Series II 3 ladder 3 Ladder 3 13
Demo DNA 7500 Series II 4 ladder DNA 7500 DNA 7500 ladder 13
Demo DNA 7500 Series II 5 ladder 5 Ladder 5 13
Demo DNA 7500 Series II 6 ladder 6 Ladder 6 13
Demo DNA 7500 Series II 7 ladder 1 Ladder 1 13
Demo DNA 7500 Series II 8 ladder 2 Ladder 2 13
Demo DNA 7500 Series II 9 ladder 3 Ladder 3 13
Demo DNA 7500 Series II 10 ladder DNA 7500 DNA 7500 ladder 13
Demo DNA 7500 Series II 11 ladder 5 Ladder 5 13
Demo DNA 7500 Series II 12 ladder 6 Ladder 6 13
Demo DNA 7500 Series II 13 Ladder DNA 7500 ladder 13
Demo DNA 12000 Series II 1 Ladder 3 Ladder 3 13
Demo DNA 12000 Series II 2 Ladder x 13
Demo DNA 12000 Series II 3 Ladder 6 Ladder 6 13
Demo DNA 12000 Series II 4 Ladder 2 Ladder 2 13
Demo DNA 12000 Series II 5 Ladder 1 13
Demo DNA 12000 Series II 6 Ladder 4 Ladder 4 13
Demo DNA 12000 Series II 7 Ladder 3 Ladder 3 13
Demo DNA 12000 Series II 8 Ladder x 13
Demo DNA 12000 Series II 9 Ladder 6 Ladder 6 13
Demo DNA 12000 Series II 10 Ladder 2 Ladder 2 13
Demo DNA 12000 Series II 11 Ladder 1 Ladder 1 13
Demo DNA 12000 Series II 12 Ladder 4 Ladder 4 13
Demo DNA 12000 Series II 13 Ladder DNA 12000_Ladder 13

The electrophoresis class

Let’s have a closer look at what we get when we open a data file:

dna1000 <- read.electrophoresis(system.file(
    "extdata",
    "bioanalyzer",
    "Demo DNA 1000 Series II.xml.gz",
    package = "bioanalyzeR"
))
class(dna1000)
#> [1] "electrophoresis"
names(dna1000)
#> [1] "data"        "assay.info"  "samples"     "peaks"       "regions"    
#> [6] "calibration"
head(dna1000$data)
sample.index time fluorescence aligned.time length concentration molarity
1 30.00 -0.0004425 33.42105 NA NA NA
1 30.05 -0.2573700 33.47368 NA -0.0008645 NA
1 30.10 -0.0841217 33.52632 NA -0.0011433 NA
1 30.15 -0.1443634 33.57895 NA -0.0007638 NA
1 30.20 -0.1733398 33.63158 NA -0.0010604 NA
1 30.25 -0.2204742 33.68421 NA -0.0013123 NA
head(dna1000$samples)
batch well.number sample.name sample.observations sample.comment ladder.well
Demo DNA 1000 Series II 1 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 2 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 3 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 4 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 5 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 6 Ladder 6 Ladder 6 13
head(dna1000$peaks)
sample.index peak.observations length time aligned.time lower.time upper.time lower.aligned.time upper.aligned.time area concentration molarity lower.length upper.length
1 Lower Marker 15.0000 39.10 43.00000 37.55 40.50 41.36842 44.47368 63.487170 4.2000000 424.242000 17.52598 18.71392
1 Possible Co-Migration of 4 Peaks 48.7340 43.15 47.26316 42.55 44.20 46.63158 48.36842 7.176994 0.5163261 16.052680 40.86092 60.78989
1 Possible Co-Migration of 2 Peaks 103.0442 49.95 54.42105 48.80 50.95 53.21052 55.47368 11.265350 0.6640159 9.763611 94.99825 109.75669
1 Questionable Peak 144.7399 55.10 59.84211 54.30 55.35 59.00000 60.10526 2.983823 0.1636650 1.713260 137.19186 146.44150
1 149.5976 55.70 60.47368 55.35 56.50 60.10526 61.31579 5.005250 0.2723388 2.758294 146.44150 156.71105
1 Possible Co-Migration of 2 Peaks 200.6069 61.35 66.42105 60.40 62.80 65.42105 67.94736 27.163960 1.2741050 9.623101 191.98248 213.74946
head(dna1000$regions)
#> NULL

Each electrophoresis object contains the main data in its $data member and has several other members with metadata like the sample names and software-reported peaks and regions of interest (though this particular example had no regions in it).

You’ll notice that many of the values at the beginning of dna1000$data are NA. This is because the mobility model (the standard curve relating migration speed to molecule length) does not extrapolate to observations below the lower marker or above the upper marker, and the estimates of concentration and molarity depend on the length. We can see some better examples if we look farther down:

head(subset(dna1000$data, ! is.na(length)))
sample.index time fluorescence aligned.time length concentration molarity
183 1 39.10 95.47542 43.00000 15.00000 0.4897247 52.83526
184 1 39.15 94.49809 43.05263 15.00377 0.4953069 53.42430
185 1 39.20 89.56355 43.10526 15.01523 0.4793073 51.65979
186 1 39.25 81.28615 43.15789 15.03459 0.4443601 47.83254
187 1 39.30 70.84047 43.21053 15.06207 0.3951816 42.46250
188 1 39.35 59.44926 43.26316 15.09788 0.3380439 36.23833

Subsetting an electrophoresis object

Because the electrophoresis class is complex, it has its own special subset method (subset.electrophoresis) to simplify subsetting. The principle is that you request a subset of the samples, and all members are automatically updated.

dna1000 <- read.electrophoresis(system.file(
    "extdata",
    "bioanalyzer",
    "Demo DNA 1000 Series II.xml.gz",
    package = "bioanalyzeR"
))
dna1000$samples
batch well.number sample.name sample.observations sample.comment ladder.well
Demo DNA 1000 Series II 1 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 2 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 3 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 4 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 5 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 6 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 7 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 8 Ladder 2 Ladder 2 13
Demo DNA 1000 Series II 9 Ladder 3 Ladder 3 13
Demo DNA 1000 Series II 10 DNA 1000 ladder Ladder DNA 1000 13
Demo DNA 1000 Series II 11 Ladder 5 Ladder 5 13
Demo DNA 1000 Series II 12 Ladder 6 Ladder 6 13
Demo DNA 1000 Series II 13 Ladder Ladder DNA 1000 13
dna1000.ladder1 <- subset(dna1000, sample.name == "Ladder 1")
dna1000.ladder1$samples
batch well.number sample.name sample.observations sample.comment ladder.well
Demo DNA 1000 Series II 1 Ladder 1 Ladder 1 13
Demo DNA 1000 Series II 7 Ladder 1 Ladder 1 13
dna1000.ladder1$peaks
sample.index peak.observations length time aligned.time lower.time upper.time lower.aligned.time upper.aligned.time area concentration molarity lower.length upper.length
1 Lower Marker 15.00000 39.10 43.00000 37.55 40.50 41.36842 44.47368 63.487170 4.2000000 424.242000 17.52598 18.71392
1 Possible Co-Migration of 4 Peaks 48.73400 43.15 47.26316 42.55 44.20 46.63158 48.36842 7.176994 0.5163261 16.052680 40.86092 60.78989
1 Possible Co-Migration of 2 Peaks 103.04420 49.95 54.42105 48.80 50.95 53.21052 55.47368 11.265350 0.6640159 9.763611 94.99825 109.75669
1 Questionable Peak 144.73990 55.10 59.84211 54.30 55.35 59.00000 60.10526 2.983823 0.1636650 1.713260 137.19186 146.44150
1 149.59760 55.70 60.47368 55.35 56.50 60.10526 61.31579 5.005250 0.2723388 2.758294 146.44150 156.71105
1 Possible Co-Migration of 2 Peaks 200.60690 61.35 66.42105 60.40 62.80 65.42105 67.94736 27.163960 1.2741050 9.623101 191.98248 213.74946
1 247.80470 66.55 71.89474 66.00 67.60 71.31579 73.00000 15.190050 0.6459550 3.949556 242.70977 257.19972
1 298.17930 72.10 77.73684 71.40 73.25 77.00000 78.94736 22.842370 0.8833409 4.488554 291.76053 308.72767
1 399.03180 81.45 87.57895 80.65 82.65 86.73684 88.84211 37.251460 1.1971060 4.545490 387.93289 416.15243
1 500.72600 87.70 94.15790 86.75 89.10 93.15789 95.63158 60.457780 1.7825220 5.393745 483.77716 525.90295
1 599.27960 92.35 99.05263 91.25 93.95 97.89474 100.73680 48.356040 1.3856860 3.503410 566.61142 623.00421
1 691.47530 96.70 103.63160 95.70 97.25 102.57890 104.21050 51.946870 1.4504850 3.178280 663.98870 703.98308
1 733.62730 97.80 104.78950 97.25 99.55 104.21050 106.63160 85.765930 2.3990110 4.954644 703.98308 799.04957
1 886.34890 100.55 107.68420 99.55 101.35 106.63160 108.52630 78.290610 2.1990900 3.759187 799.04957 970.04909
1 1062.70300 102.10 109.31580 101.35 104.50 108.52630 111.84210 111.507300 3.0126590 4.295300 970.04909 1371.69818
1 Upper Marker 1500.00000 105.60 113.00000 104.60 107.00 111.94740 114.47370 81.828600 2.1000000 2.121210 1384.01736 1630.29054
2 Lower Marker 15.00000 38.10 43.00000 36.50 39.80 41.22925 44.88142 60.471110 4.2000000 424.242000 17.86830 21.40719
2 Possible Co-Migration of 4 Peaks 49.37152 42.00 47.31620 41.45 43.00 46.70751 48.42292 7.704427 0.4866122 14.933520 41.82392 61.32174
2 Possible Co-Migration of 2 Peaks 104.15310 48.55 54.56522 47.45 49.40 53.34782 55.50593 12.328830 0.6406598 9.319897 95.82338 109.98622
2 Questionable Peak 144.58620 53.30 59.82213 52.50 53.55 58.93676 60.09881 3.557921 0.1724338 1.806971 136.66853 146.38707
2 149.69360 53.90 60.48617 53.55 54.70 60.09881 61.37154 5.903490 0.2836979 2.871497 146.38707 157.18610
2 Possible Co-Migration of 2 Peaks 200.96380 59.30 66.46245 58.45 60.45 65.52174 67.73518 29.403260 1.2173120 9.177821 192.85111 211.92376
2 247.24690 64.15 71.83004 63.60 64.90 71.22134 72.66008 17.541650 0.6596678 4.042501 241.89770 254.27345
2 297.82420 69.45 77.69566 68.40 70.45 76.53360 78.80238 25.624100 0.8758825 4.455963 287.71502 307.45631
2 398.68740 78.35 87.54546 77.40 79.55 86.49407 88.87353 41.578320 1.1809730 4.488104 384.92614 416.60226
2 Possible Co-Migration of 2 Peaks 501.28730 84.35 94.18578 83.60 85.75 93.35574 95.73518 93.347700 2.4307890 7.347105 487.08608 527.70940
2 595.99160 88.60 98.88933 87.90 90.25 98.11463 100.71540 60.722940 1.5385310 3.911305 570.73404 622.55101
2 689.58220 92.80 103.53760 91.80 93.40 102.43080 104.20160 66.136880 1.6321430 3.586145 660.54011 703.75347
2 734.58020 93.95 104.81030 93.40 95.50 104.20160 106.52570 98.885480 2.4436170 5.040221 703.75347 792.58413
2 875.31400 96.45 107.57710 95.55 97.25 106.58100 108.46250 96.875570 2.4111390 4.173631 795.92295 962.87061
2 1046.80200 97.90 109.18180 97.25 100.50 108.46250 112.05930 128.535800 3.0735300 4.448652 962.87061 1396.98969
2 Upper Marker 1500.00000 101.35 113.00000 100.55 102.75 112.11460 114.54940 92.634490 2.1000000 2.121210 1403.35261 1635.65406

You can see that in addition to dna1000.ladder1$samples, $peaks and other members have also been reduced to data from the remaining samples even though they don’t contain the sample.observations variable themselves. Instead, the sample.index column has been updated to point to the new row numbers of those samples in the $samples table.

Combining electrophoresis objects

The electrophoresis class also has a special method for combining multiple instances into one, which is rbind (rbind.electrophoresis) since most members are data frames and multiple instances should have the same columns. However, this special rbind method automatically updates the sample.index columns and concatenates the other members that are not data frames.

dna1000 <- read.electrophoresis(system.file(
    "extdata",
    "bioanalyzer",
    "Demo DNA 1000 Series II.xml.gz",
    package = "bioanalyzeR"
))
dna7500 <- read.electrophoresis(system.file(
    "extdata",
    "bioanalyzer",
    "Demo DNA 7500 Series II.xml.gz",
    package = "bioanalyzeR"
))
unique(dna1000$data$sample.index)
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13
unique(dna7500$data$sample.index)
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13
combined.batches <- rbind(dna1000, dna7500)
unique(combined.batches$data$sample.index)
#>  [1]  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] 26
combined.batches$assay.info
#> $`Demo DNA 1000 Series II`
#> $`Demo DNA 1000 Series II`$file.name
#> [1] "C:\\Program Files (x86)\\Agilent\\2100 bioanalyzer\\2100 expert\\data\\samples\\demo\\electrophoresis\\Demo DNA 1000 Series II.xad"
#> 
#> $`Demo DNA 1000 Series II`$creation.date
#> [1] "2005-12-14T08:03:40.000"
#> 
#> $`Demo DNA 1000 Series II`$assay.name
#> [1] "DNA 1000 Series II"
#> 
#> $`Demo DNA 1000 Series II`$assay.type
#> [1] "DNA"
#> 
#> $`Demo DNA 1000 Series II`$length.unit
#> [1] "bp"
#> 
#> $`Demo DNA 1000 Series II`$concentration.unit
#> [1] "ng/µl"
#> 
#> $`Demo DNA 1000 Series II`$molarity.unit
#> [1] "nM"
#> 
#> $`Demo DNA 1000 Series II`$method
#> [1] "hyman"
#> 
#> 
#> $`Demo DNA 7500 Series II`
#> $`Demo DNA 7500 Series II`$file.name
#> [1] "C:\\Program Files (x86)\\Agilent\\2100 bioanalyzer\\2100 expert\\data\\samples\\demo\\electrophoresis\\Demo DNA 7500 Series II.xad"
#> 
#> $`Demo DNA 7500 Series II`$creation.date
#> [1] "2005-12-14T09:56:52.000"
#> 
#> $`Demo DNA 7500 Series II`$assay.name
#> [1] "DNA 7500 Series II"
#> 
#> $`Demo DNA 7500 Series II`$assay.type
#> [1] "DNA"
#> 
#> $`Demo DNA 7500 Series II`$length.unit
#> [1] "bp"
#> 
#> $`Demo DNA 7500 Series II`$concentration.unit
#> [1] "ng/µl"
#> 
#> $`Demo DNA 7500 Series II`$molarity.unit
#> [1] "nM"
#> 
#> $`Demo DNA 7500 Series II`$method
#> [1] "hyman"

The rbind method is automatically used to combine multiple batches in read.electrophoresis, so if you use that function to import the batches at the same time, you probably will not need to rbind them later.

Drawing electropherograms

qplot.electrophoresis

The members of an electrophoresis object that contain graphable data are data frames compatible with ggplot2. However, the metadata by sample are in the $samples member while the actual electrophoresis data are kept separately in the $data member. To simplify graphing, this package includes the qplot.electrophoresis function, which is analogous to ggplot2::qplot but has slightly different syntax: in particular, the first argument is the electrophoresis object, and the x- and y-variables have defaults.

d1000 <- read.electrophoresis(system.file(
    "extdata",
    "tapestation",
    "D1000-Tubes-16-D1000.xml.gz",
    package = "bioanalyzeR"
))
qplot.electrophoresis(d1000, title = "TapeStation D1000")

This produces plots analogous to the electropherograms in the Agilent software. However, with the default settings there are several differences; these settings are described in the next sections.

Data, peaks, and regions

qplot.electrophoresis displays the software-reported peaks as filled area under the curve. You can stop displaying peaks by setting show.peaks = "none":

qplot.electrophoresis(
    d1000,
    show.peaks = "none",
    title = "TapeStation D1000 with no peaks"
)

Or you can include the markers with include.markers = TRUE and fill only the marker peaks with show.peaks = "markers", though it’s difficult to see them without changing the axis variables (explained later):

qplot.electrophoresis(
    d1000,
    x = "relative.distance",
    y = "fluorescence",
    include.markers = TRUE,
    show.peaks = "markers",
    title = "TapeStation D1000 with marker peaks"
)

Reported regions of interest are shown as semitransparent gray rectangles; you can modify the transparency of these or set it to NA to stop displaying regions:

qplot.electrophoresis(
    d1000,
    region.alpha = 0.5,
    title = "TapeStation D1000 with darker regions"
)

qplot.electrophoresis(
    d1000,
    region.alpha = NA,
    title = "TapeStation D1000 with no regions"
)

Finally, the readings from the samples themselves are plotted by default as a continuous curve (ggplot2::geom_line). The other supported geom is geom_area, which (as in qplot) you get by setting geom = "area":

eukrna <- read.electrophoresis(system.file(
    "extdata",
    "tapestation",
    "Eukaryotic RNA-Tubes-16-RNA.xml.gz",
    package = "bioanalyzeR"
))
qplot.electrophoresis(
    eukrna,
    y = "concentration",
    xlim = c(100, NA),
    title = "TapeStation Eukaryotic RNA with geom_line"
)

qplot.electrophoresis(
    eukrna,
    y = "concentration",
    xlim = c(100, NA),
    geom = "area",
    title = "TapeStation Eukaryotic RNA with geom_area"
)

Data ranges

You can easily zoom in on an interesting feature by setting the xlim or ylim arguments (note that you can leave a limit as NA to let the software choose):

qplot.electrophoresis(
    eukrna,
    y = "concentration",
    xlim = c(100, 2000),
    ylim = c(NA, 0.08),
    title = "TapeStation Eukaryotic RNA zoomed in"
)
#> Warning: Removed 730 rows containing missing values (position_stack).
#> Warning: Removed 1428 row(s) containing missing values (geom_path).

Or you can use the scales argument, which is passed to ggplot2::facet_wrap or ggplot2::facet_grid, to allow different facets to automatically get different axis scales:

qplot.electrophoresis(
  eukrna,
    y = "concentration",
    xlim = c(100, 2000),
    scales = "free_y",
    title = "TapeStation Eukaryotic RNA with free y-scales"
)

Another difference from the electropherograms in the software is that, by default, the x-axis (molecule length) is in a linear scale. In the Agilent software, data points are simply graphed as they appeared to the instrument and the x-axis labels are roughly (but not exactly; see stdcrv.mobility below) logarithmic. You can log-scale the axes with the log argument that behaves the same as in ggplot2::qplot:

qplot.electrophoresis(
    eukrna,
    y = "concentration",
    xlim = c(100, 2000),
    log = "x",
    title = "TapeStation Eukaryotic RNA with log x-scale"
)
#> Scale for 'x' is already present. Adding another scale for 'x', which will
#> replace the existing scale.

qplot.electrophoresis(
    eukrna,
    y = "concentration",
    xlim = c(100, 2000),
    log = "xy",
    title = "TapeStation Eukaryotic RNA with log x- and y-scales"
)
#> Scale for 'x' is already present. Adding another scale for 'x', which will
#> replace the existing scale.

Of course, log-scaling the y-axis gives weird results when the values are fractional.

Changing the axis variables

By now you have probably noticed that the y-axis displays molarity or concentration rather than fluorescence. In fact it displays molarity per length (the molarity estimate for each point is scaled with the differential.scale function) so that the area under a curve, between any two x-values, is directly proportional to the molarity of molecules in that range.

If you change the y-variable to y = "fluorescence" you can see something closer to the electropherograms from the Agilent software:

ladder1 <- subset(d1000, sample.name == "ladder")
qplot.electrophoresis(
    ladder1,
    y = "fluorescence",
    title = "TapeStation D1000 ladder fluorescence"
)

This is still not quite the same as the electropherograms from the Agilent software because the x-axis is linear. You could log-scale it as above, but to get a truly analogous graph you can simply change the x-variable to relative.distance, which for TapeStation data is the migration distance normalized to the markers (the capillary instruments have aligned.time instead):

qplot.electrophoresis(
    ladder1,
    x = "relative.distance",
    y = "fluorescence",
    title = "TapeStation D1000 ladder fluorescence vs. distance"
)

Note that the x-axis is automatically reversed when the x-variable is distance, to keep the plots in the same orientation.

Compare fluorescence with concentration:

qplot.electrophoresis(
    ladder1,
    y = "concentration",
    title = "TapeStation D1000 ladder concentration"
)

Even though differential-scaled concentration is more directly informative than raw fluorescence, for many experiments the real variable of interest is molarity. Rather than the total mass of molecules, we want to know the number of molecules. The problem is that the mass concentration, and therefore the fluorescence, depends on the length of the molecule: a 2 kb fragment has approximately twice the mass and twice the fluorescence of a 1 kb fragment, even if the copy number is the same. So that is the default y-value:

qplot.electrophoresis(
    ladder1,
    title = "TapeStation D1000 ladder molarity"
)

If our variable of interest was molarity, the concentration graph would have been very misleading! And the original fluorescence vs. distance graph even moreso.

Or sometimes the absolute variable is irrelevant and what we really want to know is the size distribution within each sample. For that you can set normalize = "total", which uses the normalize.proportion function to scale the variable of interest to a proportion of the sample’s total, i.e. the total area under every curve (between the markers) is 1. Notice how the different dilutions of the same sample become roughly equal after normalization, until very low dilutions:

d1000.96 <- read.electrophoresis(system.file(
    "extdata",
    "tapestation",
    "D1000-Plate-96-D1000.xml.gz",
    package = "bioanalyzeR"
))
qplot.electrophoresis(
    subset(d1000.96, startsWith(as.character(sample.name), "frag. lambda DNA")),
    facets = NULL,
    xlim = c(100, 800),
    title = "TapeStation D1000"
)

qplot.electrophoresis(
    subset(d1000.96, startsWith(as.character(sample.name), "frag. lambda DNA")),
    facets = NULL,
    xlim = c(100, 800),
    normalize = "total",
    title = "TapeStation D1000 normalized"
)