igvteam / igv.js

Embeddable genomic visualization component based on the Integrative Genomics Viewer
MIT License
636 stars 224 forks source link

Local fasta file is fully loaded #1767

Closed jpofmars closed 5 months ago

jpofmars commented 5 months ago

Dear All,

I'm trying to create my own reference. I first used a local fasta downloaded from Ensembl, but the sequence didn't display in the browser and the file was fully loaded as you can see in the image while the index was loaded fine.

Capture d’écran 2024-02-16 à 15 29 57

If I use the links as described in the documentation, everything works fine. I tried to download the fasta from the given url and to use it as previously, but it doesn't work. Strangely enough, if I use the local index file 'hg38.fa.fai' with the Amazon link for the fasta, it works.

I include the IGV browser in a vuejs component. IGV was install with NPM.

Thank you for your help.

<template>
    <div class="w-full p-4 mb-6 bg-white border rounded-lg">
        <div id="igv-div" ref="igv"></div>
    </div>
</template>

<script setup>

const props = defineProps({
    coordinates: Object,
    mode: String,
});

import { ref, onMounted } from 'vue';

let igvDiv = ref(null);

let options = ref(
    {
        genome: "hg38",
        loadDefaultGenomes: false,
        locus: props.coordinates.chr + ":" + props.coordinates.start + "-" + props.coordinates.end,
       reference: {
            id: "hg38",
            // fastaURL: "/storage/data-igv/Homo_sapiens.GRCh38.dna.primary_assembly.fa",
            // indexURL: "/storage/data-igv/Homo_sapiens.GRCh38.dna.primary_assembly.fa.fai",
            fastaURL: "/storage/data-igv/hg38.fa",
            indexURL: "/storage/data-igv/hg38.fa.fai",
            // fastaURL: "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa",
            // indexURL: "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa.fai",
            cytobandURL: "/storage/data-igv/cytoBandIdeo.txt.gz",
            name: "Human hg38/GRCh38",
            indexed: true,

        }
    });

const initIgvBrowser = () => {

    igvDiv.value = document.getElementById("igv-div");

    igv.createBrowser(igvDiv.value, options.value)
        .then(function (browser) {
            console.log("Created IGV browser");
        })

};

onMounted(() => {

    initIgvBrowser();
});

</script>
jpofmars commented 5 months ago

To complete it seems i have the same issue with tracks. The gff3.gz file is fully loaded even if tbi was loaded.


 tracks: [
                {
                    name: 'Ensembl Genes',
                    url: '/storage/data-igv/Homo_sapiens.GRCh38.111.sorted.gff3.gz',
                    indexURL: "/storage/data-igv/Homo_sapiens.GRCh38.111.sorted.gff3.gz.tbi",
                    type: "annotation",
                    format: 'gff3',
                    displayMode: "expanded",
                    height: 300,
                    visibilityWindow: 500000,
                    colorBy: "biotype",
                    colorTable: {
                        "antisense": "blueviolet",
                        "protein_coding": "blue",
                        "retained_intron": "rgb(0, 150, 150)",
                        "processed_transcript": "purple",
                        "processed_pseudogene": "#7fff00",
                        "unprocessed_pseudogene": "#d2691e",
                        "*": "black"
                    },
                    "searchable": true

                },
jrobinso commented 5 months ago

You cannot use local file paths with javascript in a web browser. Are the paths in the URL fields local file paths?

jpofmars commented 5 months ago

It is a real URL not a path. In vuejs '/storage/data-igv/Homo_sapiens.GRCh38.111.sorted.gff3.gz' is translate in http://127.0.0.1:8000'/storage/data-igv/Homo_sapiens.GRCh38.111.sorted.gff3.gz' I put the files in a public folder.

I try to use the git version IGV.js instead of npm, I get the same error.

jrobinso commented 5 months ago

Most probably your webserver is not supporting range-byte requests, or not correctly doing so.

jpofmars commented 5 months ago

Yes, I'm exploring different possibilities and I think this is it. In dev mode, (I develop in laravel + vuejs) I use php artisan serve. The prod version will be with nginx. I'll look into it. Thanks for your help.

jpofmars commented 5 months ago

I found the solution for a laravel application. So I give it:

first add these lines to the .htaccess file

 <FilesMatch "\.(mp4|pdf|jpg|jpeg|png|gif|gz|bam|cram|fa)$"> // add extension if necessary
        Header set Accept-Ranges bytes
    </FilesMatch>

Next in web.php file add a route like this :

Route::prefix('igv')->controller(IgvController::class)->group(function () {
        Route::get('/filedata/{fichier}',  'getFile');
    });

And then in your controller create a function getfile :

public function getFile($file)
    {
        $datafolder = 'path/to/files'; // not necessary in public, could be where you want
        $filepath = $datafolder.'/'.$file;
        if (!file_exists($filepath)) {
            return response()->json(['message' => 'file not found'], 404);
        }
        if (str_ends_with($file, '.gz')) { // Complete with necessary extension file
            $headers = [
                'Content-Type' => 'application/gzip',
            ];
        } elseif (str_ends_with($file, '.bam') || str_ends_with($file, '.bai') || str_ends_with($file, '.cram') || str_ends_with($file, '.tbi') || str_ends_with($file, '.fai')) {
            $headers = [
                'Content-Type' => 'application/octet-stream',
            ];
        } else {
            $headers = [
                'Content-Type' => 'text/plain',
            ];
        }

        return response()->file($filepath, $headers);
    }

In your vue module call the file like this in your track or reference:

reference: { id: "hg38", fastaURL: "/igv/filedata/hg38.fa", indexURL: "/igv/filedata/hg38.fa.fai" }

jrobinso commented 5 months ago

Wow a lot of setup is required for that web server.

Is there a reason you are restricting range byte support to certain file types?

This is particularly important if your web server improperly marks bam, cram, and bai content as 'application/gzip':

elseif (str_ends_with($file, '.bam') || str_ends_with($file, '.bai') || str_ends_with($file, '.cram') || str_ends_with($file, '.tbi') || str_ends_with($file, '.fai')) {
            $headers = [
                'Content-Type' => 'application/octet-stream',
            ];

There is also a bug with Apache, it sometimes improperly sets "content encoding" to gzip for these files. This is documented along with other data server requirements here: https://github.com/igvteam/igv.js/wiki/Data-Server-Requirements

I'm going to close this as there is no igv.js issue per se here.