This is a test version of Biostars. For the public version, visit https://www.biostars.org.
IGV - Load custom variant track

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?

vcf igv react

0 answers

No answers yet.

Log in to answer this question.