Skip to content
Snippets Groups Projects
Select Git revision
  • 60353fb38b129fe1f88a0b19e96332abeb8fdcd9
  • main default protected
2 results

dataloaders.py

Blame
  • StructureDb.vue 12.79 KiB
    <script setup lang="ts">
    import type { SortItem, AutocompleteMeiliFacetProps } from "@/components/ServerDbTable.vue"
    import { useNumericalFilter } from "@/composables/useNumericalfilter"
    import { useRefinedUrl } from "@/composables/useRefinedUrl"
    import { ServerDbTable } from "#components"
    
    import { joinURL } from 'ufo'
    import { useStructuresBasket } from "~/stores/structuresBasket"
    
    interface Item {
        Foldseek_name: string
        system: string
    }
    
    
    const sortBy: Ref<SortItem[]> = ref([{ key: 'system', order: "asc" }])
    const itemValue = ref("id");
    const dbName = ref("structure")
    const client = useMeiliSearchRef()
    const structureTitle = ref("Structure")
    const structureBasket = useStructuresBasket()
    
    
    onMounted(async () => {
    
        try {
            const data = await client.index(toValue(dbName)).search("", {
                facets: ["*"],
                filter: [],
                page: 1,
                hitsPerPage: 25,
            })
            autocompleteMeiliFacetsProps.value.facetDistribution = data?.facetDistribution
        } catch (error) {
            throw createError("Unable to get structures")
    
        }
    
    
    
    })
    
    
    
    const autocompleteMeiliFacetsProps = ref<AutocompleteMeiliFacetProps>({
        db: toValue(dbName),
        facets: [
            { title: "Defense System", type: "subheader" },
            { title: "System", value: "system", type: "facet", icon: "i-tabler:virus-off", },
            { title: "Subsystem", value: "subsystem", type: "facet", icon: "i-tabler:virus-off" },
            { type: "divider" },
            { title: "Completed", value: "completed", type: "facet", icon: "md:done" },
            { title: "Prediction type", value: "prediction_type", type: "facet", icon: "i-gravity-ui:molecule" },
        ],
        facetDistribution: undefined
    })
    
    
    
    const computedAutocompleteMeiliFacetsProps = computed(() => {
        const toValFacetDistribution = toValue(autocompleteMeiliFacetsProps).facetDistribution
        const toValFacets = toValue(autocompleteMeiliFacetsProps).facets
        if (toValFacetDistribution !== undefined && toValFacets !== undefined) {
            return {
                ...toValue(autocompleteMeiliFacetsProps), facets: toValFacets.map(facet => {
                    if (facet.type === "facet") {
                        const count = toValFacetDistribution?.[facet.value] ? Object.keys(toValFacetDistribution[facet.value]).length : undefined
    
                        return count ? { ...facet, count } : { ...facet }
                    }
                    else {
                        return { ...facet }
                    }
                })
            }
        }
        else {
            return toValue(autocompleteMeiliFacetsProps)
        }
    })
    
    
    const headers: Ref<Object[]> = ref([
        { title: 'Structure', key: 'structure', sortable: false, removable: false, fixed: true, minWidth: "110px" },
        { title: 'Foldseek', key: 'Foldseek_name', sortable: false },
        { title: "System", key: "system", removable: false },
        // { title: "Gene name", key: "gene_name", removable: false },
        { title: "Sub-system", key: "subsystem", removable: false },
        // { title: "pdb file", key: "pdb" },
        // { title: "fasta", key: "fasta_file" },
        { title: "Proteins in structure", key: 'proteins_in_the_prediction', sortable: false, removable: true },
        { title: "System genes", key: "system_genes", sortable: false, removable: true },
        { title: "Sys id", key: "nb_sys", removable: true },
    
        { title: "Completed", key: "completed", removable: true },
        { title: "Prediction type", key: "prediction_type", removable: true },
        { title: "N genes in sys", key: "system_number_of_genes", removable: true },
        { title: "pLDDT", key: "plddts", removable: true },
        { title: "iptm+ptm", key: "iptm+ptm", removable: true },
        { title: "pDockQ", key: "pDockQ", removable: true },
        // { title: "Type", key: "type", removable: true },
    
    ])
    
    const { range: plddtsRange, stringifyFilter: plddtsFilter, reset: plddtsReset } = useNumericalFilter("plddts", 0, 100)
    const { range: iptmRange, stringifyFilter: iptmFilter, reset: iptmReset } = useNumericalFilter("iptm+ptm", 0, 1)
    const { range: pdockqRange, stringifyFilter: pdockqFilter, reset: pdockqReset } = useNumericalFilter("pDockQ", 0, 1)
    
    
    function isString(item: Ref<string | undefined>): item is Ref<string> {
        return toValue(item) !== undefined
    
    }
    
    const numericalFilters = computed(() => {
        const listFilters = [plddtsFilter, iptmFilter, pdockqFilter].filter(isString).map(f => toValue(f))
        return listFilters.length > 0 ? listFilters : undefined
    })
    
    const defaultDataTableServerProps = ref({
        showExpand: false
    })
    
    const dataTableServerProps = computed(() => {
        return {
            ...toValue(defaultDataTableServerProps),
            headers: toValue(headers),
            itemValue: toValue(itemValue)
        }
    })
    
    
    
    function toFolseekUrl(item: Item) {
        const url = joinURL("/" + item.system, item.Foldseek_name)
        const { refinedUrl } = useRefinedUrl(url)
        return toValue(refinedUrl)
    }
    
    function extractGeneName(name: string) {
        if (name.includes("__")) {
            return name.split("__")[1]
        }
        if (name.includes("_")) {
            return name.split("_")[1]
        }
        return undefined
    }
    
    function namesToCollapsibleChips(names: string[], systemDir: string, file: string | null = null) {
        if (file === null) {
            return names.filter((it) => it !== "").map(it => ({ title: extractGeneName(it) }))
        } else {
            return names.filter((it) => it !== "").map(it => ({ title: extractGeneName(it), href: `/wiki/${systemDir}/${file}` }))
        }
    }
    
    function pdbNameToCif(pdbPath: string) {
        const cifPath = pdbPath.split(".").slice(0, -1).join(".")
        return `${cifPath}.cif`
    }
    
    
    function buildStructureUrl(item) {
        return [`/${item.system}/${pdbNameToCif(item.pdb)}`, `/${item.system}/${item.pdb}`]
    }
    
    function displayStructure(item) {
    
        structureBasket.set(buildStructureUrl(item).map(url => {
            return toValue(useRefinedUrl(url).refinedUrl)
        }))
        structureTitle.value = `${item.subtype} - ${item.gene_name}`
    
    }
    const { refinedUrl: downloadAllPdbUrl } = useRefinedUrl("/df-all-pdbs.tar.gz")
    const { refinedUrl: downloadAllCifUrl } = useRefinedUrl("/df-all-cifs.tar.gz")
    
    </script>
    <template>
        <v-card>
            <ServerDbTable title="Predicted Structures" :sortBy="sortBy" :data-table-server-props="dataTableServerProps"
                :autocomplete-meili-facets-props="computedAutocompleteMeiliFacetsProps"
                :numerical-filters="toRef(numericalFilters)">
                <template #numerical-filters="{ search }">
                    <v-card-text>
                        <v-row>
                            <v-col cols="12" md="4">
                                <v-card flat variant="tonal">
                                    <v-card-item class="mb-4">
                                        <v-card-title> pLDDT
                                        </v-card-title>
                                    </v-card-item>
                                    <v-card-text class="pr-0">
                                        <v-range-slider v-model="plddtsRange" strict density="compact" hide-details="auto"
                                            class="" step="0.5" :min="0" :max="100" thumb-label="always"
                                            @update:modelValue="search()">
                                            <template #append>
                                                <v-btn variant="text" density="compact" icon="md:restart_alt"
                                                    @click="plddtsReset()"></v-btn>
                                            </template>
    
                                        </v-range-slider>
                                    </v-card-text>
                                </v-card>
                            </v-col>
                            <v-col cols="12" md="4">
                                <v-card flat variant="tonal">
                                    <v-card-item class="mb-4">
                                        <v-card-title> iptm+ptm
                                        </v-card-title>
                                    </v-card-item>
                                    <v-card-text class="pr-0">
                                        <v-range-slider v-model="iptmRange" strict density="compact" hide-details="auto"
                                            step="0.1" :min="0" :max="1" thumb-label="always" @update:modelValue="search()">
                                            <template #append>
                                                <v-btn variant="text" density="compact" icon="md:restart_alt"
                                                    @click="iptmReset()"></v-btn>
                                            </template>
                                        </v-range-slider>
                                    </v-card-text></v-card>
                            </v-col>
    
                            <v-col cols="12" md="4">
                                <v-card flat variant="tonal">
                                    <v-card-item class="mb-4">
                                        <v-card-title> pDockQ
                                        </v-card-title>
                                    </v-card-item>
                                    <v-card-text class="pr-0">
                                        <v-range-slider v-model="pdockqRange" density="compact" strict hide-details="auto"
                                            step="0.1" :min="0" :max="1" thumb-label="always" @update:modelValue="search()">
                                            <template #append>
                                                <v-btn variant="text" density="compact" icon="md:restart_alt"
                                                    @click="pdockqReset()"></v-btn>
                                            </template>
                                        </v-range-slider>
                                    </v-card-text>
                                </v-card>
                            </v-col>
                        </v-row>
                    </v-card-text>
                </template>
                <template #[`item.Foldseek_name`]="{ item }">
                    <FoldseekDialog v-if="item.Foldseek_name !== 'na'" :foldseek-path="toFolseekUrl(item)"></FoldseekDialog>
    
                </template>
                <template #[`item.proteins_in_the_prediction`]="{ item }">
                    <CollapsibleChips
                        :items="namesToCollapsibleChips(item.proteins_in_the_prediction, item.system, item.fasta_file)">
                    </CollapsibleChips>
                </template>
                <template #[`item.system_genes`]="{ item }">
                    <CollapsibleChips :items="namesToCollapsibleChips(item.system_genes, item.system)">
                    </CollapsibleChips>
                </template>
                <template #[`item.structure`]="{ item }">
                    <v-row justify="space-between" dense no-gutters align="center">
                        <v-col>
                            <v-btn size="x-small" variant="text" icon="md:visibility"
                                @click="displayStructure(item)"></v-btn>
                        </v-col>
                        <v-col>
                            <v-menu>
                                <template v-slot:activator="{ props }">
                                    <v-btn :disabled="item.structuresUrls?.length < 1" size="x-small" variant="text"
                                        icon="md:download" class="ml-1" v-bind="props"></v-btn>
                                </template>
                                <v-list>
                                    <v-list-item v-for="(url, index) in item.structuresUrls" :key="index" :value="index"
                                        :href="url">
                                        <v-list-item-title>{{ url.split('.').slice(-1)[0] }}</v-list-item-title>
                                    </v-list-item>
                                </v-list>
                            </v-menu>
                        </v-col>
                    </v-row>
                </template>
                <template #[`item.completed`]="{ item }">
                    <v-icon v-if="item.completed" color="success" icon="md:check"></v-icon>
                    <v-icon v-else color="warning" icon="md:dangerous"></v-icon>
                </template>
                <template #toolbar-items>
                    <v-menu>
                        <template v-slot:activator="{ props }">
                            <!-- <v-tooltip activator="parent" location="top">Download all structures</v-tooltip> -->
                            <v-btn class="align-self-end" v-bind="props" icon="md:download">
                            </v-btn>
                        </template>
                        <v-list>
                            <v-list-item value="pdb" :href="downloadAllPdbUrl">
                                <v-list-item-title>all pdbs</v-list-item-title>
                            </v-list-item>
                            <v-list-item value="cif" :href="downloadAllCifUrl">
                                <v-list-item-title>all cifs</v-list-item-title>
                            </v-list-item>
                        </v-list>
                    </v-menu>
                </template>
            </ServerDbTable>
            <PdbeMolstarPlugin v-model="stuctureUrls" v-model:title="structureTitle" />
        </v-card>
    </template>