Skip to content
Snippets Groups Projects
Commit 59e3f5a5 authored by Remi  PLANEL's avatar Remi PLANEL
Browse files

WIP

parent 9454e8fc
No related branches found
No related tags found
No related merge requests found
Pipeline #128474 failed
<script setup lang="ts">
import { useElementSize } from '@vueuse/core'
import * as d3 from "d3";
import type { PlotMargin, StructureOperonGene } from "../types/plot";
import type { PlotMargin } from "../types/plot";
import type { StructureOperonGene } from "../types/structure"
import { useStructuresBasket } from '~/stores/structuresBasket';
interface Props {
genes: StructureOperonGene[] | null
}
const structureBasket = useStructuresBasket()
const props = withDefaults(defineProps<Props>(), {
genes: null
});
const height = ref<number>(75)
const height = ref<number>(150)
const svgRef = ref(null)
const margin = ref<PlotMargin>({
marginTop: 10,
marginRight: 0,
marginBottom: 20,
marginLeft: 0,
marginRight: 5,
marginBottom: 30,
marginLeft: 5,
})
const plotHeight = computed(() => {
......@@ -38,11 +40,14 @@ const yScale = ref(d3.scaleBand()
const gbContainer = ref(null)
const gbContainerWidth = ref(useElementSize(gbContainer, { width: 500, height: 0 }, { box: 'border-box' }).width)
const computedWidth = computed(() => {
const computedContainerWidth = computed(() => {
return gbContainerWidth.value
})
const computedPlotWidth = computed(() => {
const { marginLeft, marginRight } = toValue(margin)
return computedContainerWidth.value - marginLeft - marginRight
})
onMounted(() => {
draw()
......@@ -61,11 +66,9 @@ const computedGenes = computed(() => {
})
watch(computedGenes, () => {
const genes = toValue(computedGenes)
console.log(genes)
const domain = genes?.map(d => { return d.gene })
console.log(domain)
xScale.value.domain(domain)
.range([0, computedWidth.value])
.range([0, computedPlotWidth.value])
})
......@@ -102,20 +105,24 @@ function createOrSelect(container, tag, selectionClass) {
function draw() {
const svg = d3.select(svgRef.value);
const { marginLeft, marginRight } = toValue(margin)
const { marginLeft } = toValue(margin)
const xAxis = d3.axisBottom(xScale.value)
const gx = createOrSelect(svg, 'g', 'x-axis')
gx
.attr("transform", `translate(${marginLeft},${toValue(height)})`)
.call(xAxis)
.selectAll("text")
.attr("transform", 'rotate(45)')
.attr("text-anchor", "start")
const gxTitle = createOrSelect(gx, "text", "x-axis-title")
gxTitle.attr("text-anchor", "end")
gxTitle
.attr("text-anchor", "end")
.attr("fill", "currentColor")
gxTitle
.attr("x", computedWidth.value - marginLeft - marginRight)
.attr("x", toValue(computedPlotWidth))
.attr("y", - 10)
......@@ -133,6 +140,7 @@ function drawGenes(genesGroup) {
const g = enter.append("g")
.classed("gene", true);
g.append("path").classed("gene", true)
g.append("image")
g.append("text")
// .attr("fill", "white")
.classed("gene-label", true)
......@@ -145,14 +153,22 @@ function drawGenes(genesGroup) {
exit => exit.remove()
)
genesSelection.attr("transform", d => `translate(${d.x},${d.y})`)
genesGroup.select("image")
.attr("href", d => d?.structImg)
.attr("width", d => d.width)
.attr("height", d => d.height)
.on("click", function (event) {
console.log(event)
const data = d3.select(this).data()
console.log(data)
structureBasket.set(data.map(s => s.structPath))
})
genesSelection.select("path.gene")
.attr("d", d => drawGene(d).toString())
}
function drawGene({ width, height }) {
console.log("dans le draw gene")
console.log(width)
console.log(height)
const context = d3.path()
context.moveTo(0, 0)
context.lineTo(width, 0)
......@@ -167,7 +183,8 @@ function drawGene({ width, height }) {
<template>
<div ref="gbContainer">
<v-card flat color="transparent">
<svg ref="svgRef" :width="computedWidth" :height="plotHeight">
<!-- <v-img :href=""></v-img> -->
<svg ref="svgRef" :width="computedContainerWidth" :height="plotHeight">
<g class="x-axis" />
</svg>
</v-card>
......
......@@ -3,13 +3,15 @@ import { toValue } from '@vueuse/core';
// import MolstarPdbePlugin from './MolstarPdbePlugin.vue';
import * as d3 from "d3";
import SystemOperonStructure from './SystemOperonStructure.vue';
import type { StructureItem } from '~/types/structure';
import type { SearchParams, SearchResponse } from 'meilisearch';
const { page } = useContent();
const client = useMeiliSearchRef()
// get the structures
const structures = ref()
const structures = ref<SearchResponse<StructureItem, SearchParams> | undefined>()
const structureTitle = ref("Structure")
const msIndexName = ref<string>("structure")
const stuctureUrls = ref<string[] | undefined>(undefined)
......@@ -62,11 +64,12 @@ function displayStructure(item) {
const sanitizedStructures = computed(() => {
const toValStructures = toValue(structures)
if (toValStructures?.hits?.length > 0) {
if (toValStructures?.hits && toValStructures?.hits?.length > 0) {
return toValStructures.hits.map(item => {
console.log(item)
return {
...item, structuresUrls: [`/${item.system}/${pdbNameToCif(item.pdb)}`, `/${item.system}/${item.pdb}`]
...item, structuresUrls: [`/${item.system.toLowerCase()}/${pdbNameToCif(item.pdb)}`, `/${item.system.toLowerCase()}/${item.pdb}`]
.map(url => {
return toValue(useRefinedUrl(url).refinedUrl)
})
......@@ -77,6 +80,7 @@ const sanitizedStructures = computed(() => {
})
const perSubsystemStructures = computed(() => {
const toValStructures = toValue(sanitizedStructures)
if (toValStructures?.length > 0) {
......@@ -89,11 +93,8 @@ const perSubsystemStructures = computed(() => {
// ASYNC PART
async function fetchStructures() {
try {
const d = await client.index(toValue(msIndexName)).search("", {
const d = await client.index(toValue(msIndexName)).search<StructureItem>("", {
facets: ["*"],
filter: [`system='${toValue(computedSystem)}'`, "completed='true'"],
})
......@@ -109,8 +110,8 @@ async function fetchStructures() {
<template v-for="[subsystem, structures] in perSubsystemStructures" :key="subsystem[0]">
<ProseH3>{{ computedSystem }} - {{ subsystem }}</ProseH3>
<v-row align="end">
<v-col cols="6">
<SystemOperonStructure :system="computedSystem" :subsystem="subsystem" />
<v-col cols="6" class="ml-0 ">
<SystemOperonStructure :system="computedSystem" :subsystem="subsystem" :structures="structures" />
</v-col>
<v-col cols="6">
<PdockqMatrix :subsystem="subsystem" />
......
<script setup lang="ts">
import { computed, toValue } from '#imports'
import { useDisplay } from "vuetify";
import { useStructuresBasket } from '~/stores/structuresBasket';
const { mobile, width, height } = useDisplay()
const structureBasket = useStructuresBasket()
useHead({
link: [
{
......@@ -50,9 +51,12 @@ const moleculeFormat = ref<string>("pdb")
const selectedPdb = ref<string | null>(null)
const structureToDownload: Ref<string | null> = ref(null)
const selectedPaePath = computed(() => {
console.log(selectedPdb)
return selectedPdb.value ? `${selectedPdb.value.split(".").slice(0, -1).join('.')}.pae.png` : undefined
})
const computedWidth = computed(() => {
// if (toValue(width) > toValue(maxWidth)) return toValue(maxWidth) / 1.5
return toValue(width) / 1.5
})
......@@ -78,7 +82,8 @@ function viewPdb(pdbPath: string | null) {
function closeStructure() {
selectedPdb.value = null
dataUrls.value = undefined
// dataUrls.value = undefined
structureBasket.set(undefined)
dialog.value = false
}
watch(selectedPdb, (newSelectedPdb, prevSelectPdb) => {
......@@ -89,10 +94,10 @@ watch(selectedPdb, (newSelectedPdb, prevSelectPdb) => {
})
watchEffect(() => {
const toValUrl = toValue(dataUrls)
if (toValUrl?.length > 0) {
const toValUrl = toValue(structureBasket).structures
if (toValUrl && toValUrl?.length > 0) {
dialog.value = true
selectedPdb.value = dataUrls.value[0]
selectedPdb.value = toValUrl[0]
}
else {
dialog.value = false
......@@ -105,7 +110,8 @@ watchEffect(() => {
<v-card flat :rounded="false">
<v-toolbar>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-select v-model="selectedPdb" label="Select PDB" :items="dataUrls" hide-details="auto"></v-select>
<v-select v-model="selectedPdb" label="Select PDB" :items="structureBasket.structures"
hide-details="auto"></v-select>
<v-spacer></v-spacer>
<v-btn :disabled="!selectedPdb" icon="md:download" :href="structureToDownload"></v-btn>
......
......@@ -179,7 +179,7 @@ function pdbNameToCif(pdbPath: string) {
return `${cifPath}.cif`
}
function buildStructureUrl(item) {
return [`/${item.system}/${pdbNameToCif(item.pdb)}`, `/${item.system}/${item.pdb}`]
return [`/${item.system.toLowerCase()}/${pdbNameToCif(item.pdb)}`, `/${item.system}/${item.pdb}`]
}
function displayStructure(item) {
......
<script setup lang="ts">
import type { StructureOperonGene } from "../../types/plot";
import type { StructureItem, StructureOperonGene } from "../../types/structure";
import type { SearchResponse } from "meilisearch";
import { withTrailingSlash, withLeadingSlash, joinURL } from 'ufo'
interface Props {
system: string
subsystem: string
structures: StructureItem[]
}
const { page } = useContent();
const { system, subsystem } = withDefaults(defineProps<Props>(), {
const { system, subsystem, structures } = withDefaults(defineProps<Props>(), {
});
const client = useMeiliSearchRef()
......@@ -17,35 +20,84 @@ const pending = ref<boolean>(false)
const msIndexName = ref<'systemoperonstruct'>("systemoperonstruct")
const msResponse = ref<SearchResponse<StructureOperonGene> | undefined>(undefined)
const monomerStructures = computed(() => {
const structuresVal = toValue(structures)
if (structuresVal) {
return structuresVal.filter(struct => {
return struct.prediction_type === "monomer"
}).map((struct) => {
return {
...struct,
structImg: `${struct.pdb.split(".pdb")[0]}.png`,
structPath: struct.pdb,
proteins_in_the_prediction: struct.proteins_in_the_prediction.map(prot => {
return prot.split("__")[1]
})
}
})
}
})
const sanitizedHits = computed(() => {
const toValMsResponse = toValue(msResponse)
if (toValMsResponse && toValMsResponse?.hits?.length > 0) {
return toValMsResponse.hits.map(hit => {
return { ...hit, gene: hit.gene.split("__")[1] }
// get structure information for this prot
const monomerStructuresVal = toValue(monomerStructures)
const sanitizedGene = hit.gene.split("__")[1]
if (monomerStructuresVal) {
const struct = monomerStructuresVal.find((struct) => {
return struct.proteins_in_the_prediction[0] === sanitizedGene
})
const rawImgUrl = joinURL(`/${system.toLowerCase()}`, struct?.structImg ?? '')
const rawStructUrl = joinURL(`/${system.toLowerCase()}`, struct?.structPath ?? '')
const { refinedUrl: structImgHref } = useRefinedUrl(rawImgUrl)
return { ...hit, gene: sanitizedGene, structImg: toValue(structImgHref), structPath: rawStructUrl}
}
else {
return { ...hit, gene: sanitizedGene }
}
})
} else {
return []
}
})
const sanitizedSystem = computed(() => {
const pageVal = toValue(page)
return pageVal?.systemModel || pageVal.title
})
const sanitizedSubsystem = computed(() => {
const pageVal = toValue(page)
const systemModel = pageVal?.systemModel
if (systemModel) {
return subsystem.replace(pageVal.title, systemModel)
}
else {
return subsystem
}
})
onMounted(() => {
fetchOperonStructure()
})
async function fetchOperonStructure() {
try {
pending.value = true
const data = await client.index(toValue(msIndexName)).search<StructureOperonGene>("", {
facets: ["*"],
filter: [`system='${system}' AND subsystem='${subsystem}'`],
filter: [`system='${toValue(sanitizedSystem)}' AND subsystem='${toValue(sanitizedSubsystem)}'`],
limit: 500000,
})
msResponse.value = data
} catch (error) {
throw createError(`Cannot get hits on refseq for system: ${system} `)
throw createError(`Cannot get hits on refseq for system: ${toValue(sanitizedSystem)} `)
} finally {
pending.value = false
}
......@@ -54,8 +106,8 @@ async function fetchOperonStructure() {
<template>
<v-card flat>
<OperonStructure :genes="sanitizedHits" />
<v-card variant="flat">
<OperonStructure :genes="sanitizedHits" :system :subsystem />
</v-card>
</template>
\ No newline at end of file
---
title: Avs
systemModel: AVAST
layout: article
tableColumns:
article:
......
......@@ -111,11 +111,11 @@ def structure(
],
):
with open(stat, "r") as stat_f:
reader = csv.DictReader(stat_f)
reader = csv.DictReader(stat_f, delimiter="\t")
count_row = 0
for row in reader:
count_row += 1
system_dir_name = row["system"]
system_dir_name = row["system"].lower()
pdb_path_file = Path(row["pdb"])
foldseek_html_file = Path(str(pdb_path_file).split(".pdb")[0] + ".html")
png_structure = Path(str(pdb_path_file).split(".pdb")[0] + ".png")
......
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useStructuresBasket = defineStore('structuresBasket', () => {
const rawStructures = ref<string[] | undefined>(undefined)
function pdbToCif(pdbPath: string) {
const cifPath = pdbPath.split(".").slice(0, -1).join(".")
return `${cifPath}.cif`
}
const structures = computed(() => {
const rawStructuresVal = toValue(rawStructures)
if (rawStructuresVal !== undefined) {
return rawStructuresVal
// add cif
.flatMap((struct) => {
return [pdbToCif(struct), struct]
})
// refinedUrl
.map((struct) => {
const { refinedUrl } = useRefinedUrl(struct)
return toValue(refinedUrl)
})
}
return rawStructuresVal
})
function set(structuresToSet: MaybeRef<string[] | undefined>) {
rawStructures.value = toValue(structuresToSet)
}
return { structures, set }
})
\ No newline at end of file
......@@ -7,9 +7,3 @@ export interface PlotMargin {
export interface StructureOperonGene {
gene: string
id: number
subsystem: string
system: string
}
\ No newline at end of file
export interface StructureOperonGene {
gene: string
id: number
subsystem: string
system: string
}
export type StructurePredictionType = "monomer" | "multimer" | "multimer(dimer)" | "multimer(homodimer)"
export type StructureType = "Validated" | "DF" | "na"
export interface StructureItem {
id: number
proteins_in_the_prediction: string[]
prediction_type: StructurePredictionType
batch: number
nb_sys: number
type: StructureType
system_number_of_genes: number
system_genes: string[]
pdb: string
pae_table: string
plddt_table: string
fasta_file: string
completed: boolean
'iptm+ptm': number | null
pDockQ: number | null
plddts: number | null
structure_system: string
system: string
subsystem: string
Abi2: string
OrbA: string
Anti_BREX: string
// "structuresUrls": ["/wiki/Avs/AVAST_I.AVAST_I__Avs1A.0.V.cif", "/wiki/Avs/AVAST_I.AVAST_I__Avs1A.0.V.pdb"]
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment