Entering edit mode
10 weeks ago
sadapas
•
0
I am trying to learn how to integrate IGV in a React app and use a VCF created from a JSON (I will pull the variant data from various APIs) but right now I can load properly the track but the track is empty. I am using a placeholder VCF just to understand how to load and display properly a track and then I will create a script to turn the APIs json in a VCF
import React, { createRef, Component } from "react";
import { convertToVCF } from "../utils/vcfUtils";
const igvStyle = {
fontFamily: "open sans, Helvetica, Arial, sans-serif",
paddingTop: "60px",
margin: "5px",
};
class IGVViewer extends Component {
constructor(props) {
super(props);
this.container = createRef(null);
}
componentDidMount() {
// Dynamically load IGV.js from a CDN
const script = document.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/igv@3.0.7/dist/igv.min.js";
script.async = true;
script.onload = () => {
const { geneData, variants, type } = this.props;
// Extract chromosome, start, and end from geneData
const chromosome = geneData?.chromosomes?.[0] || "14"; // Default chromosome
const start =
geneData?.annotations?.[0]?.genomic_locations?.[0]?.genomic_range
?.begin || 33800027;
const end =
geneData?.annotations?.[0]?.genomic_locations?.[0]?.genomic_range
?.end || 33851710;
// Ensure locus string matches IGV format: "chromosome:start-end"
const locus = `${chromosome}:${start}-${end}`;
// Default Genome ID (use placeholders for other types)
let genomeID = "GCA_000002305.1"; // Default Genome ID
if (type === "ROS_Cfam_1.0") {
genomeID = "GCA_000002305.1"; // Genome ID for ROS_Cfam_1.0
} else if (type === "CanFam3.1") {
genomeID = "GCA_placeholder1"; // Genome ID for CanFam3.1
} else if (type === "BROADD2") {
genomeID = "GCA_placeholder2"; // Genome ID for BROADD2
} else if (type === "Felis_catus_9.0") {
genomeID = "GCA_placeholder3"; // Genome ID for Felis_catus_9.0
} else if (type === "Felis_catus_6.2") {
genomeID = "GCA_placeholder4"; // Genome ID for Felis_catus_6.2
} else if (type === "EquCab3.0") {
genomeID = "GCA_placeholder5"; // Genome ID for EquCab3.0
} else if (type === "EquCab2") {
genomeID = "GCA_placeholder6"; // Genome ID for EquCab2
}
// Define a list of track names to remove (configurable)
const tracksToRemove = [
"Augustus",
"Sine",
"Simple Repeats",
"SINE",
"RNA",
"Other",
"Satellite",
"Simple",
"LINE",
"LTR",
"Low Complexity",
"CpG Islands",
];
// Dynamically create VCF header with genome and locus information
const vcfData = `
##fileformat=VCFv4.2
##fileDate=20241011
##source=EnsemblRESTAPI
##reference=file:///seq/references/${genomeID}
##contig=<ID=${chromosome},length=${end},assembly=${genomeID},md5=f126cd8f8a6e0c7f37f9d618ff66beb2da,species="Canis lupus familiaris",taxonomy=x>
##phasing=partial
##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data">
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency">
##INFO=<ID=AA,Number=1,Type=String,Description="Ancestral Allele">
##INFO=<ID=DB,Number=0,Type=Flag,Description="dbSNP membership">
##FILTER=<ID=q10,Description="Quality below 10">
##FILTER=<ID=s50,Description="Less than 50% of samples have data">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=GQ,Number=1,Type=Integer,Description="Genotype Quality">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read Depth">
#CHROM POS ID REF ALT QUAL FILTER INFO
14 33800027 rs6054257 A G 29 PASS NS=3;DP=14;AF=0.5
14 33810027 rs6040355 G T 67 PASS NS=3;DP=10;AF=0.333
14 33820027 rsTest123 T C 50 PASS NS=3;DP=9
`.trim(); // Trim the string to avoid extra spaces
// IGV options, using GenArk genome reference and default locus
const igvOptions = {
genome: genomeID, // Use GenArk genome ID
locus: locus,
tracks: [], // No tracks initially
};
// Initialize IGV browser
window.igv
.createBrowser(this.container.current, igvOptions)
.then((browser) => {
console.log("IGV Viewer successfully loaded.", browser);
// Ensure correct Base64 encoding of the VCF
const vcfBase64 = btoa(unescape(encodeURIComponent(vcfData)));
console.log("VCF Data (Base64):", vcfBase64);
// Create a track from the Base64-encoded VCF
const track = {
name: "Kahl",
format: "vcf",
url: "data:text/plain;base64," + vcfBase64,
indexed: false,
type: "variant",
displayMode: "EXPANDED", // Options: COLLAPSED, SQUISHED, EXPANDED
color: "#FF0000", // You can choose a color for the variants
height: 100, // Set a reasonable height for the track
};
// Load the track into IGV after the locus is set
browser
.search(locus)
.then(() => {
browser.loadTrack(track).then(() => {
console.log("Kahl track successfully loaded.");
// Now ensure the track removal happens after track loading is done
setTimeout(() => {
tracksToRemove.forEach((trackName) => {
const trackToRemove = browser.tracks.find(
(track) => track.name === trackName
);
if (trackToRemove) {
console.log(`Removing ${trackName} track.`);
browser.removeTrack(trackToRemove);
}
});
}, 1000); // Add a short delay to allow for all loading to complete
});
})
.catch((error) => {
console.error("Error setting locus or loading track:", error);
});
})
.catch((error) => {
console.error("Error loading IGV:", error);
});
};
document.body.appendChild(script);
}
render() {
return <div id="igv-div" ref={this.container} style={igvStyle}></div>;
}
}
export default IGVViewer;
Also do I have to load all the tracks and then filter them out?