Commit 4aabe687 authored by Mathieu Giraud's avatar Mathieu Giraud
Browse files

Merge branch 'feature-ct/mrd_brasil_tool_and_client' into 'dev'

Feature ct/mrd brasil tool and client

See merge request !781
parents ea426df6 4c03088a
Pipeline #192667 failed with stages
in 16 seconds
......@@ -91,6 +91,7 @@ function loadAfterConf() {
"../vidjil_vmi",
"../../test/QUnit/testFiles/data_test",
], function(){
if (typeof main == "undefined"){
require(["../main"]);
}else{
......@@ -99,6 +100,8 @@ function loadAfterConf() {
if (typeof config.addons !== "undefined") {
require(config.addons);
}
require(["../screen_MRD"]);
})
})
},
......
......@@ -1333,8 +1333,26 @@ Clone.prototype = {
var time_length = this.m.samples.order.length
var html = ""
var header = function(content) { return "<tr><td class='header' colspan='" + (time_length + 1) + "'>" + content + "</td></tr>" ; }
var row_1 = function(item, content) { return "<tr><td>" + item + "</td><td colspan='" + time_length + "'>" + content + "</td></tr>" ; }
// Functions to format html row
var clean_title = function(title){ return title.replace(/[&\/\\#,+()$~%.'":*?<>{} ]/gi,'_').replace(/__/gi,'_')}
var header = function(content, title) {
title = (title == undefined) ? clean_title(content) : clean_title(title)
return "<tr id='modal_header_"+title+"'><td class='header' colspan='" + (time_length + 1) + "'>" + content + "</td></tr>" ;
}
var row_1 = function(item, content, title) {
title = (title == undefined) ? clean_title(item) : clean_title(title)
return "<tr id='modal_line_"+title+"'><td id='modal_line_title_"+title+"'>" + item + "</td><td colspan='" + time_length + "' id='modal_line_value_"+title+"'>" + content + "</td></tr>" ;
}
var row_from_list = function(item, content, title) {
title = (title == undefined) ?clean_title(item) : clean_title(title)
var div = "<tr id='modal_line_"+title+"'><td id='modal_line_title_"+title+"'>"+ item + "</td>"
for (var i = 0; i < content.length; i++) {
col = content[i]
div += "<td id='modal_line_value_"+title+"_"+i+"'>" + col + "</td>"
}
div += "</tr>" ;
return div;
}
if (isCluster) {
html = "<h2>Cluster info : " + this.getName() + "</h2>"
......@@ -1356,9 +1374,22 @@ Clone.prototype = {
//warnings
if (this.isWarned()) {
html += header("warnings")
var warnings = {}
// Create a dict of all warning present, and add each sample with it
// One warning msg by entrie, without duplication.
for (i = 0; i < this.warn.length; i++) {
html += row_1(this.warn[i].code, this.warn[i].msg);
if (this.warn[i] != 0 && this.warn[i] != undefined){
if (warnings[this.warn[i].msg] == undefined){
warnings[this.warn[i].msg] = {"code":this.warn[i].code, "msg": this.warn[i].msg, "samples":[i]}
} else {
warnings[this.warn[i].msg].samples.push(i)
}
}
}
// put warning html content, with list of concerned sample, without duplication
for (var warn in warnings) {
var pluriel = warnings[warn].samples.length > 1 ? "s" : ""
html += row_1(warnings[warn].code, warnings[warn].msg);
}
}
......@@ -1394,6 +1425,15 @@ Clone.prototype = {
for (var k = 0; k < time_length; k++) {
html += "<td>" + this.getStrSize(this.m.samples.order[k]) + "</td>"
}
// Specific part for MRD script
if ('mrd' in this && this.getHtmlInfo_prevalent != undefined){
values = this.getHtmlInfo_prevalent()
for (var mrd_val = 0; mrd_val < values.length; mrd_val++) {
html += row_from_list(values[mrd_val][0], values[mrd_val][1], values[mrd_val][2])
}
}
html += header("representative sequence")
}else{
html += header("sequence")
......@@ -1451,7 +1491,7 @@ Clone.prototype = {
if (this.hasSizeConstant()) {
html += header("segmentation" +
" <button type='button' onclick='m.clones["+ this.index +"].toggle()'>edit</button>" + //Use to hide/display lists
this.getHTMLModifState()) // icon if manual changement
this.getHTMLModifState(), "segmentation") // icon if manual changement
} else {
html += header("segmentation")
}
......@@ -1970,6 +2010,8 @@ Clone.prototype = {
return x.equals(axes)
}
},
};
......
/*
* This file is part of Vidjil <http://www.vidjil.org>,
* High-throughput Analysis of V(D)J Immune Repertoire.
* Copyright (C) 2013-2020 by Bonsai bioinformatics
* at CRIStAL (UMR CNRS 9189, Université Lille) and Inria Lille
* Contributors:
* Joao Meidanis <joao.m@boldrini.org.br>
* The Vidjil Team <contact@vidjil.org>
*
* "Vidjil" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "Vidjil" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "Vidjil". If not, see <http://www.gnu.org/licenses/>
*/
/**
* Adding functionality to the Clone object so that it can display MRD
* estimates obtained from the .vidjil file as modified by
* spike-normalization.py in the info box.
*
* The Clone methods added here are new
* The exception of getHtmlInfo-prevalent is call if needed from
* getHTMLInfo function of Clone prototype.
* Coding conventions and comment styles are borrowed from clone.js.
*/
UNIVERSAL_FAMILY = "UNI"
UNIVERSAL_COEFF = 'UNI_COEFF'
UNIVERSAL_R2 = 'UNI_R2'
function ScreenMRD() {}
ScreenMRD.prototype = {
/**
* @return {string} the family used for fiting at the given time
*/
getFittingFamily : function(time) {
if (this.m.mrd.prevalent[time] == 0) {
// diagnostic sample
return "";
} else if (this.mrd != undefined && 'family' in this.mrd) {
return this.mrd.family[time];
} else {
// negative clone: report UNI
return UNIVERSAL_FAMILY;
}
},
/**
* @return {string} the normalization coefficient at the given time
*/
getNormCoeff : function(time) {
if (this.m.mrd.prevalent[time] == 0) {
// diagnostic sample
return "";
} else if (this.mrd != undefined && 'norm_coeff' in this.mrd) {
return this.mrd.norm_coeff[time];
} else if (UNIVERSAL_COEFF in this.m.mrd) {
// negative clone:report UNI
return this.m.mrd.UNI_COEFF[time];
} else {
return "";
}
},
/**
* @return {string} the Pearson R2 value for the spike-in fitting at the given time
*/
getR2 : function(time) {
if (this.m.mrd.prevalent[time] == 0) {
// diagnostic sample
return "";
} else if (this.mrd != undefined && 'R2' in this.mrd) {
return this.mrd.R2[time]//.toString();
} else if (UNIVERSAL_R2 in this.m.mrd) {
// negative clone: report UNI R2
return this.m.mrd.UNI_R2[time];
} else {
return "";
}
},
/**
* @return {string} the prevalent germline at the given time
*/
getPrevalent : function(time) {
if (this.m.mrd.prevalent[time] == 0) {
// diagnostic sample
return "";
} else {
return this.m.mrd.prevalent[time];
}
},
/**
* @return {string} the amplification coefficient at the given time
* (ampl. coeff. = total prevalent / total spike)
*/
getAmplCoeff : function(time) {
if (this.m.mrd.prevalent[time] == 0) {
// diagnostic sample
return "";
} else if ('ampl_coeff' in this.m.mrd) {
return this.m.mrd.ampl_coeff[time]//.toString();
} else {
return "Please use version 6 or later of spike-normalization";
}
},
/**
* Return info about a sequence/clone in html
*/
getHtmlInfo_prevalent : function () {
values = []
if ('mrd' in this) {
// this .vidjil file is not all-diagnostic:
// show R2, etc, fields for follow-up samples
content_fitting_family = []
content_norm_coeff = []
content_getR2 = []
content_getPrevalent = []
content_getAmplCoeff = []
for (k = 0; k < this.m.samples.order.length; k++) {
var sample = this.m.samples.order[k]
// Get prevalent value
var prevalent = this.getPrevalent(sample)
if (prevalent != ""){
prevalent = this.m.systemBox(prevalent).outerHTML + prevalent
}
content_getPrevalent.push( prevalent )
// Computed values
content_fitting_family.push( this.getFittingFamily(sample) )
content_norm_coeff.push( this.getNormCoeff(sample))
content_getR2.push( this.getR2(sample) )
content_getAmplCoeff.push( this.getAmplCoeff(sample) )
}
// include values into html
// name of col, values to show, and DOM id for cells
values.push(["prevalent germline", content_getPrevalent, "mrd_prevalent"])
values.push(["family used for fitting", content_fitting_family, "mrd_family"])
values.push(["normalization coefficient", content_norm_coeff, "mrd_norm_coeff"])
values.push(["Pearson R2", content_getR2, "mrd_pearson"])
values.push(["total prevalent / total spikes", content_getAmplCoeff, "mrd_prevalent_on_spike"])
}
return values
}
}
Clone.prototype = $.extend(Object.create(ScreenMRD.prototype), Clone.prototype);
\ No newline at end of file
......@@ -228,21 +228,33 @@ QUnit.test("name, informations, getHtmlInfo", function(assert) {
assert.includes(html, "<div id='info_window'><table><tr><th></th><td>Diag</td><td>Fu-1</td><td>Fu-2</td><td>Fu-3</td></tr>",
"getHtmlInfo: cluster info");
assert.includes(html, "<tr><td>clone name</td><td colspan='4'>hello</td></tr><tr><td>clone short name</td><td colspan='4'>hello</td></tr>",
assert.includes(html, "tr id='modal_line_clone_name'><td id='modal_line_title_clone_name'>clone name</td><td colspan='4' id='modal_line_value_clone_name'>hello</td></tr>",
"getHtmlInfo: clone names")
assert.includes(html, "<tr><td>clone size (n-reads (total reads))</td><td>20 (200)</td><td>20 (100)</td><td>30 (200)</td><td>30 (100)</td></tr><tr><td>clone size (%)</td><td>10.00%</td><td>20.00%</td><td>15.00%</td><td>30.00%</td>",
"getHtmlInfo: clone information");
assert.includes(html, "<tr><td class='header' colspan='5'>representative sequence</td></tr><tr><td>sequence name</td><td colspan='4'>hello</td></tr><tr><td>code</td><td colspan='4'>hello</td></tr><tr><td>length</td><td colspan='4'>19</td></tr><tr><td>e-value</td><td colspan='4'><span class='warning'>0.01</span></td></tr><tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information");
assert.includes(html, "<tr><td class='header' colspan='5'>segmentation <button type='button' onclick='m.clones[0].toggle()'>edit</button></td></tr><tr><td>sequence</td><td colspan='4'>aaaaaaaaaattttttttt</td></tr><tr><td>id</td><td colspan='4'>id1</td></tr>",
"getHtmlInfo: segmentation information + modification button");
assert.includes(html, "<tr id='modal_line_sequence_name'><td id='modal_line_title_sequence_name'>sequence name</td><td colspan='4' id='modal_line_value_sequence_name'>hello</td></tr><tr id='modal_line_code'><td id='modal_line_title_code'>code</td><td colspan='4' id='modal_line_value_code'>hello</td></tr><tr id='modal_line_length'><td id='modal_line_title_length'>length</td><td colspan='4' id='modal_line_value_length'>19</td></tr><tr id='modal_line_e-value'><td id='modal_line_title_e-value'>e-value</td><td colspan='4' id='modal_line_value_e-value'><span class='warning'>0.01</span></td></tr><tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; sequence name");
assert.includes(html, "<tr id='modal_line_code'><td id='modal_line_title_code'>code</td><td colspan='4' id='modal_line_value_code'>hello</td></tr><tr id='modal_line_length'><td id='modal_line_title_length'>length</td><td colspan='4' id='modal_line_value_length'>19</td></tr><tr id='modal_line_e-value'><td id='modal_line_title_e-value'>e-value</td><td colspan='4' id='modal_line_value_e-value'><span class='warning'>0.01</span></td></tr><tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; code");
assert.includes(html, "<tr id='modal_line_length'><td id='modal_line_title_length'>length</td><td colspan='4' id='modal_line_value_length'>19</td></tr><tr id='modal_line_e-value'><td id='modal_line_title_e-value'>e-value</td><td colspan='4' id='modal_line_value_e-value'><span class='warning'>0.01</span></td></tr><tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; length");
assert.includes(html, "<tr id='modal_line_e-value'><td id='modal_line_title_e-value'>e-value</td><td colspan='4' id='modal_line_value_e-value'><span class='warning'>0.01</span></td></tr><tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; evalue");
assert.includes(html, "<tr><td>size (n-reads (total reads))</td><td>10 (200)</td><td>10 (100)</td><td>0 (200)</td><td>30 (100)</td></tr><tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; size total");
assert.includes(html, "<tr><td>size (%)</td><td>5.000%</td><td>10.00%</td><td>−</td><td>30.00%</td></tr>",
"getHtmlInfo: representative sequence information; size %");
assert.includes(html, "<tr id='modal_header_segmentation'><td class='header' colspan='5'>segmentation <button type='button' onclick='m.clones[0].toggle()'>edit</button></td></tr>",
"getHtmlInfo: segmentation information + modification button; header");
assert.includes(html, "<tr id='modal_line_sequence'><td id='modal_line_title_sequence'>sequence</td><td colspan='4' id='modal_line_value_sequence'>aaaaaaaaaattttttttt</td></tr>",
"getHtmlInfo: segmentation information + modification button; content");
// Test icon
m.clones[0].segEdited = true;
html = m.clones[0].getHtmlInfo();
assert.includes(html, "<tr><td class='header' colspan='5'>segmentation <button type='button' onclick='m.clones[0].toggle()'>edit</button> <img src='images/icon_fav_on.png' alt='This clone has been edited by a user'></td></tr><tr><td>sequence</td><td colspan='4'>aaaaaaaaaattttttttt</td></tr><tr><td>id</td><td colspan='4'>id1</td></tr>",
assert.includes(html, "<tr id='modal_header_segmentation'><td class='header' colspan='5'>segmentation <button type='button' onclick='m.clones[0].toggle()'>edit</button> <img src='images/icon_fav_on.png' alt='This clone has been edited by a user'></td></tr>",
"getHtmlInfo: segmentation information + modification button + manuallyChanged icon");
// <tr><td>locus</td><td colspan='4'><span title=\"TRG\" class=\"systemBoxMenu\">G</span>TRG</td></tr> // not tested (order of title/class)
......@@ -253,11 +265,11 @@ QUnit.test("name, informations, getHtmlInfo", function(assert) {
/*assert.includes(html, "<tr><td>locus</td><td colspan='4'><span title=\"TRG\" class=\"systemBoxMenu\">G</span>TRG<div class='div-menu-selector' id='listLocus' style='display: none'>",
"getHtmlInfo: segmentation information (Locus)");*/
assert.includes(html, "<tr><td>V gene (or 5')</td><td colspan='4'>undefined V<div class='div-menu-selector' id='listVsegment' style='display: none'>",
assert.includes(html, "<tr id='modal_line_V_gene_or_5_'><td id='modal_line_title_V_gene_or_5_'>V gene (or 5')</td><td colspan='4' id='modal_line_value_V_gene_or_5_'>undefined V<div class='div-menu-selector' id='listVsegment' style='display: none'><form name=Vsegment>",
"getHtmlInfo: segmentation information (V gene)");
assert.includes(html, "<tr><td>(D gene)</td><td colspan='4'>IGHD2*03<div class='div-menu-selector' id='listDsegment' style='display: none'>",
assert.includes(html, "<tr id='modal_line__D_gene_'><td id='modal_line_title__D_gene_'>(D gene)</td><td colspan='4' id='modal_line_value__D_gene_'>IGHD2*03<div class='div-menu-selector' id='listDsegment' style='display: none'><form name=Dsegment><select class='menu-selector' NAME=Dsegment onChange='m.clones[0].changeSegment(this.form.Dsegment.value, 4);' style='width: 100px' >",
"getHtmlInfo: segmentation information (D gene)");
assert.includes(html, "<tr><td>J gene (or 3')</td><td colspan='4'>IGHV4*01<div class='div-menu-selector' id='listJsegment' style='display: none'>",
assert.includes(html, "<tr id='modal_line_J_gene_or_3_'><td id='modal_line_title_J_gene_or_3_'>J gene (or 3')</td><td colspan='4' id='modal_line_value_J_gene_or_3_'>IGHV4*01<div class='div-menu-selector' id='listJsegment' style='display: none'><form name=Jsegment>",
"getHtmlInfo: segmentation information (J gene)");
// forms tests
......@@ -280,16 +292,16 @@ QUnit.test("name, informations, getHtmlInfo", function(assert) {
"<option value=IGH>IGH</option><option value=TRA>TRA</option>",
"getHtmlInfo: first options in select locus (after changment)"); // after germline changment
assert.includes(html,
"<tr><td>V gene (or 5')</td><td colspan='4'>testV5<div class='div-menu-selector' id='listVsegment' style='display: none'>",
"<tr id='modal_line_V_gene_or_5_'><td id='modal_line_title_V_gene_or_5_'>V gene (or 5')</td><td colspan='4' id='modal_line_value_V_gene_or_5_'>testV5<div class='div-menu-selector' id='listVsegment' style='display: none'><form name=Vsegment>",
"getHtmlInfo: segmentation information (V gene) after changment");
// Test junction in html export
assert.includes(html, "<tr><td>junction</td><td colspan='4'>att</td></tr>",
assert.includes(html, "<tr id='modal_line_junction'><td id='modal_line_title_junction'>junction</td><td colspan='4' id='modal_line_value_junction'>att</td></tr>",
"getHtmlInfo c1: junction info for productive clone");
html = c3.getHtmlInfo();
assert.includes(html, "<tr><td>junction</td><td colspan='4'>aaaaaaaatttt</td></tr>",
assert.includes(html, "<tr id='modal_line_junction'><td id='modal_line_title_junction'>junction</td><td colspan='4' id='modal_line_value_junction'>aaaaaaaatttt</td></tr>",
"getHtmlInfo c3: junction info for non productive clone");
assert.includes(html, "<tr><td>junction (AA seq)</td><td colspan='4'>WKIC</td></tr>",
assert.includes(html, "<tr id='modal_line_junction_AA_seq_'><td id='modal_line_title_junction_AA_seq_'>junction (AA seq)</td><td colspan='4' id='modal_line_value_junction_AA_seq_'>WKIC</td></tr>",
"getHtmlInfo c3: junction (AAseq) info for non productive clone");
// test sequence if not prsent
html = c5.getHtmlInfo();
......@@ -339,7 +351,7 @@ QUnit.test("name, informations, getHtmlInfo", function(assert) {
include = html.includes("current clone size")
assert.ok(include, "getHtmlInfo: if no sequence, field 'current clone size'");
// gene V
assert.includes(html, "<tr><td>V gene (or 5')</td>",
assert.includes(html, "<tr id='modal_line_V_gene_or_5_'><td id='modal_line_title_V_gene_or_5_'>V gene (or 5')</td>",
"getHtmlInfo: distrib clone with seg5 have field segment V");
// Sequence
......
{
"clones": [
{
"germline": "IGK",
"id": "AACAGTATAATAGTTCGCTCAGGGGGCGAGGGAATGAATTCACTTTCGGC",
"normalized_reads": [
195.50763372699805
],
"reads": [
269
],
"seg_stat": {
"3": 269
},
"sequence": 0,
"top": 231,
"mrd": {
"R2": [
0.95
],
"copy_number": [41.37324910738808],
"family": [
"UNI"
]
}
},
{
"_average_read_length": [
150.88140869140625
],
"_coverage": [
0.987530529499054
],
"_coverage_info": [
"149 bp (98% of 150.9 bp)"
],
"germline": "IGK",
"id": "CTGTCAACAGAGTTACAGTACCCCTCGGACGTTCGGCCAAGGGACCAAGG",
"name": "IGKV1D-39*01 1//2 IGKJ1*01",
"normalized_reads": [
766.0410630046689
],
"reads": [
1054
],
"seg": {},
"seg_stat": {
"3": 1054
},
"sequence": "CAAGGTTCAGCGGCAGTGGATCTGGGACAGATTTCACTCTCACCATCAGCAGTCTGCAACCTGAAGATTTTGCAACTTACTACTGTCAACAGAGTTACAGTACCCCTCGGACGTTCGGCCAAGGGACCAAGGTGGAGATCAAACGTAAG",
"top": 10,
"mrd": {
"R2": [
0.96
],
"copy_number": [162.10931062894807],
"family": [
"UNI"
]
}
},
{
"_average_read_length": [
150.7296142578125
],
"_coverage": [
0.9951594471931458
],
"_coverage_info": [
"150 bp (99% of 150.7 bp)"
],
"germline": "IGH",
"id": "GCCTCGGACACCGCCATGCCAAAACGGGGATAGCTACTGGTACTTCGATC",
"label": "Boldrini-VH5-C",
"name": "Boldrini-VH5-C IGHV5-51*05 0/CCAAAACGGGGATAG/0 IGHJ2*01",
"reads": [
7282
],
"seg": {},
"seg_stat": {
"3": 7282
},
"sequence": "TCACCATCTCAGCCGACAAGTCCATCAGCACCGCCTACCTGCAGTGGAGCAGCCTGAAGGCCTCGGACACCGCCATGCCAAAACGGGGATAGCTACTGGTACTTCGATCTCTGGGGCCGTGGCACCCGGGTCACCGTCTCCTCAGGTAAG",
"top": 1
},
{
"germline": "unexpected",
"id": "GCGAAACAAGGGCCCCGAGTGGGGGAGGATGCTTTTGATATGTGGGACCA",
"reads": [
1
],
"seg_stat": {
"3": 1
},
"sequence": 0,
"top": 38430
},
{
"germline": "IGH",
"id": "TTTTTTTTTTTTCAAGCAGAAGACGGCATACGAGATCAGCCTCGGTCTCG",
"reads": [
1
],
"seg_stat": {
"3": 1
},
"sequence": 0,
"top": 15
}
],
"config": {
"all": false,
"alternative-genes": "0",
"analysis-e-value-D": "0.05",
"analysis-filter": "1",
"cdr3": true,
"clean-memory": false,
"cluster-N": "10",
"cluster-epsilon": "0",
"cluster-load-matrix": false,
"cluster-save-matrix": false,
"consensus-on-longest-sequences": false,
"dir": "./out/",
"e-value": "1",
"germline": "germline/homo-sapiens.g",
"help-advanced": false,
"label-filter": false,
"label-json": "docker/vidjil-server/conf/boldrini/Boldrini-spikes.json",
"labels": [
{
"copies": "10",
"family": "VH1",
"name": "Boldrini-VH1-A",
"reads": 0,
"sequence": "TTTTGAAGGATGGTAG",
"vfam": "VH1"
},
{
"copies": "40",
"family": "VH1",
"name": "Boldrini-VH1-B",
"reads": 0,
"sequence": "TGCGAGACATTCTTTTGACTACT",
"vfam": "VH1"
},
{
"copies": "160",
"family": "VH1",
"name": "Boldrini-VH1-C",
"reads": 0,
"sequence": "AGATCGGGGGGGAGGGTTCGGGGAGTTTTCCCCCGCCCATT",
"vfam": "VH1"
},
{
"copies": "10",
"family": "VH2",
"name": "Boldrini-VH2-A",
"reads": 0,
"sequence": "CCCCAACCCAGACCCCGTCTTTTCCTGGTCCGTTCGTATT",
"vfam": "VH2"
},
{
"copies": "40",
"family": "VH2",
"name": "Boldrini-VH2-B",
"reads": 0,
"sequence": "ACACAGCCACGTATTACTGCCCCTTGGCCTCCTCAATTACGATATTTTGACTGGTTATCCTACTGGGGCCAGGGAACCCT",
"vfam": "VH2"
},
{
"copies": "160",
"family": "VH2",
"name": "Boldrini-VH2-C",
"reads": 0,
"sequence": "GGACACAGCCACATATTACTGTGCACGGAAGGGACCTTTACGATTTTTGGAGTGGTTATTAGGCCCTCTTACTACGGTATGGACGTCTGGGG",
"vfam": "VH2"
},
{
"copies": "10",
"family": "VH3",
"name": "Boldrini-VH3-A",
"reads": 0,
"sequence": "ATAGCAGCTCGCTCACAGA",
"vfam": "VH3"
},
{
"copies": "40",
"family": "VH3",
"name": "Boldrini-VH3-B",
"reads": 0,
"sequence": "AGGTGAGATCGGGG",
"vfam": "VH3"
},
{
"copies": "160",
"family": "VH3",
"name": "Boldrini-VH3-C",
"reads": 0,
"sequence": "TTACTGTCCTCCCGAACGAACCCCTCCGAACCCCCTATAGCAGCTCGGAGTATGGGTGTCAAACTACTACGGTAT",
"vfam": "VH3"
},
{
"copies": "40",
"family": "VH4",
"name": "Boldrini-VH4-B",
"reads": 0,
"sequence": "GGGGATGGTCAGTGG",
"vfam": "VH4"
},
{
"copies": "160",
"family": "VH4",
"name": "Boldrini-VH4-C",
"reads": 0,
"sequence": "TGTATTACTGTGCGAGAAGGGGTATAGCAGCAGCTGGTGCCTACTTTGACTACTGGGGCCAGGGAACCCT",
"vfam": "VH4"
},
{
"copies": "10",
"family": "VH5",
"name": "Boldrini-VH5-A",
"reads": 0,
"sequence": "GCGAGACGGG",
"vfam": "VH5"
},
{
"copies": "40",
"family": "VH5",
"name": "Boldrini-VH5-B",
"reads": 0,
"sequence": "CCCTCCGCCACCCTGAGAGCCCACCTGGGGGAGGTTTGA",
"vfam": "VH5"
},
{
"copies": "160",
"family": "VH5",
"name": "Boldrini-VH5-C",
"reads": 7282.0,
"sequence": "ATGCCAAAACGGGGA",
"vfam": "IGHV5"
},
{
"copies": "10",