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

remove x axis and put gene label manually

parent 831cc1df
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,7 @@
import { useElementSize } from '@vueuse/core'
import * as d3 from "d3";
import type { PlotMargin } from "../types/plot";
import type { StructureOperonGene, StructureOperonGeneWithCoordinate, StructureOperonGeneWithImg } from "../types/structure"
import type { StructureGeneLinks, StructureOperonGene, StructureOperonGeneWithCoordinate, StructureOperonGeneWithImg } from "../types/structure"
import { useStructuresBasket } from '~/stores/structuresBasket';
......@@ -69,7 +69,7 @@ const xScaleGenes = computed(() => {
const yScale = ref(d3.scaleBand()
.paddingInner(0.5)
.domain(['img', 'buff', 'buff2', 'gene'])
.domain(['img', 'buff', 'buff2', 'gene', 'label'])
.range([toValue(margin).marginTop, toValue(height)]));
const gbContainer = ref(null)
const computedContainerWidth = computed(() => {
......@@ -124,12 +124,15 @@ const structureNodes = computed<StructureOperonGeneWithCoordinate[]>(() => {
// const position = xScaleVal(d.position)
// const geneCenter = xScaleVal(d.position) + geneWidth / 2
// const xPostion = geneCenter - r / 2
const x = xScaleVal(d.gene)
const y = yScaleVal('img')
return {
...d,
r: r,
// x: xPostion > 0 ? xPostion : 0,
x: xScaleVal(d.gene),
y: yScaleVal('img'),
x: x === undefined ? 0 : x,
y: y === undefined ? 0 : y,
width: toValue(xScale).bandwidth(),
// width: r,
height: yScaleVal.step() * 3
......@@ -145,11 +148,13 @@ const geneNodes = computed<StructureOperonGeneWithCoordinate[]>(() => {
const yScaleVal = toValue(yScale)
if (genes !== null) {
return genes.map(d => {
const x = xScaleVal(d.position)
const y = yScaleVal('gene')
return {
...d,
width: xScaleVal(d.size),
x: xScaleVal(d.position),
y: yScaleVal('gene'),
x,
y: y === undefined ? 0 : y,
height: yScaleVal.bandwidth()
}
})
......@@ -157,7 +162,7 @@ const geneNodes = computed<StructureOperonGeneWithCoordinate[]>(() => {
else { return [] }
})
const linksGenesStruct = computed(() => {
const linksGenesStruct = computed<StructureGeneLinks[]>(() => {
const geneNodesVal = toValue(geneNodes)
const structureNodesVal = toValue(structureNodes)
......@@ -165,13 +170,20 @@ const linksGenesStruct = computed(() => {
return {
source: [source.x + source.width / 2, source.y],
target: [target.x + target.width / 2, target.y + target.height / 2 + 30],
highlight: source?.highlight || target?.highlight
highlight: source?.highlight || target?.highlight || false
}
})
})
const genesLabel = computed(() => {
const geneNodesVal = toValue(geneNodes)
const yScaleVal = toValue(yScale)
return geneNodesVal.map(d => ({ ...d, y: yScaleVal("label") }))
})
onMounted(() => {
// const genePropsVal = toValue(genesProps)
// refGenes.value = genePropsVal?.map(d => d)
......@@ -187,57 +199,57 @@ watch(geneNodes, () => {
draw()
})
function createOrSelect(container: d3.Selection<SVGElement, any, HTMLElement | null, any>, tag: string, selectionClass: string) {
let selection = container.select(`${tag}.${selectionClass}`)
/**
* create or select within a container a svg element and return it
* @param container
* @param tag
* @param selectionClass
*/
function createOrSelect<Type extends d3.BaseType, ParentType extends d3.BaseType>(container: d3.Selection<ParentType, any, SVGElement | null, any>, tag: string, selectionClass: string) {
let selection = container.select<Type>(`${tag}.${selectionClass}`)
if (selection.empty()) {
selection = container.append(tag).classed(selectionClass, true)
selection = container.append<Type>(tag).classed(selectionClass, true)
}
return selection
}
function draw() {
if (svgRef.value !== null) {
const svg = d3.select<SVGElement, undefined>(svgRef.value);
const svg = d3.select<SVGElement, any>(svgRef.value);
const { marginLeft, marginTop } = toValue(margin)
const xAxis = d3.axisBottom(xScaleGenes.value)
const gx = createOrSelect(svg, 'g', 'x-axis')
gx
.attr("transform", `translate(${marginLeft},${toValue(height) + marginTop})`)
.call(xAxis)
gx.call(g => g.select(".domain")
.remove())
.selectAll("text")
.attr("transform", 'rotate(20)')
.attr("text-anchor", "start")
let gOperon = createOrSelect(svg, "g", "operon")
// const xAxis = d3.axisBottom(xScaleGenes.value)
const gx = createOrSelect<SVGGElement, SVGElement>(svg, 'g', 'x-axis')
// gx
// .attr("transform", `translate(${marginLeft},${toValue(height) + marginTop})`)
// .call(xAxis)
// gx.call(g => g.select(".domain")
// .remove())
// .selectAll("text")
// .attr("transform", 'rotate(20)')
// .attr("text-anchor", "start")
let gOperon = createOrSelect<SVGGElement, SVGElement>(svg, "g", "operon")
gOperon
.attr("transform", `translate(${marginLeft},0)`)
.call(drawLinks)
.call(drawGenes)
.call(drawStructure)
.call(drawGenesLabel)
}
}
function adjacentlinks(nodes: Record<string, any>) {
const links = []
for (let i = 0; i < nodes.length; i++) {
if (i < nodes.length - 1) {
links.push({ index: i, source: nodes[i], target: nodes[+1] })
}
}
return links
}
function drawLinks(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
const stroke = "#555" // stroke for links
function drawLinks(operonGroup: d3.Selection<SVGGElement, any, SVGElement | null, any>) {
const strokeWidth = 1.5 // stroke width for links
const strokeOpacity = 0.4 // stroke opacity for links
const updateSelection = operonGroup
.selectAll("path.link")
.selectAll<SVGPathElement, StructureGeneLinks>("path.link")
.data(linksGenesStruct.value)
.join("path")
.classed("link", true)
......@@ -252,7 +264,7 @@ function drawLinks(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>)
.attr("d", d3.link(d3.curveBumpY))
}
function drawStructure(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
function drawStructure(operonGroup: d3.Selection<SVGGElement, any, SVGElement | null, any>) {
const structureNodeVal = toValue(structureNodes)
// const totalSize = domainGenes.value[1]
......@@ -276,19 +288,12 @@ function drawStructure(operonGroup: d3.Selection<SVGElement, any, SVGElement, an
gStructure
.append("image")
.on("mouseover", function (event) {
const srcSelection = d3.select(event.srcElement)
const target = d3.select(event.srcElement.parentElement)
const srcSelection = d3.select<SVGElement, StructureOperonGeneWithCoordinate>(event.srcElement)
const node = srcSelection.data()
geneToHighlight.value = node[0].gene
target
.attr("cursor", "pointer")
})
.on("mouseout", function (event) {
const target = d3.select(event.srcElement.parentElement)
target
.attr("cursor", "unset")
geneToHighlight.value = null
})
......@@ -299,7 +304,8 @@ function drawStructure(operonGroup: d3.Selection<SVGElement, any, SVGElement, an
exit => exit.remove()
)
const imageSelection = structureSelection
.attr("transform", d => `translate(0,${toValue(yScale)("img")})`)
.attr("transform", `translate(0,${toValue(yScale)("img")})`)
.attr("cursor", d => d.highlight ? "pointer" : null)
.select("image")
imageSelection
.transition()
......@@ -318,22 +324,26 @@ function drawStructure(operonGroup: d3.Selection<SVGElement, any, SVGElement, an
}
function drawGenes(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
function drawGenes(operonGroup: d3.Selection<SVGGElement, any, SVGElement | null, any>) {
const genesWithCoordVal = toValue(geneNodes)
const genes = genesWithCoordVal
const links = adjacentlinks(genes)
const genesSelection = operonGroup
.selectAll("g.operon-item") // get all "existing" lines in svg
.data<StructureOperonGeneWithCoordinate>(genes) // sync them with our data
.join(
enter => {
const gOperonItem = enter.append("g")
.classed("operon-item", true);
.classed("operon-item", true)
.on("mouseover", function (event) {
const srcSelection = d3.select<SVGElement, StructureOperonGeneWithCoordinate>(event.srcElement)
const node = srcSelection.data()
geneToHighlight.value = node[0].gene
})
.on("mouseout", function (event) {
geneToHighlight.value = null
})
// gene grp
const gGene = gOperonItem.append("g")
.classed("gene-grp", true)
......@@ -380,11 +390,58 @@ function drawGenes(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>)
context.lineTo(width, height)
context.lineTo(0, height)
context.closePath()
return context
}
}
function drawGenesLabel(operonGroup: d3.Selection<SVGGElement, any, SVGElement | null, any>) {
const genes = toValue(genesLabel)
const updateSelection = operonGroup
.selectAll<SVGGElement, StructureOperonGeneWithCoordinate>("g.gene-label")
.data<StructureOperonGeneWithCoordinate>(genes)
.join(
enter => {
const labelSelection = enter
.append("g")
.classed("gene-label", true)
.on("mouseover", function (event) {
const srcSelection = d3.select<SVGElement, StructureOperonGeneWithCoordinate>(event.srcElement)
const node = srcSelection.data()
geneToHighlight.value = node[0].gene
})
.on("mouseout", function (event) {
geneToHighlight.value = null
})
labelSelection
.append("text")
.attr("fill", "currentColor")
.attr("dominant-baseline", "middle")
labelSelection.append("title")
return labelSelection
},
update => update,
exit => exit.remove()
)
updateSelection.select("text")
.attr("transform", d => `translate(${d.x + d.width / 2},${d.y}) rotate(40) `)
.attr("style", d => d.highlight ? "font-weight: 700" : null)
.text(d => d.gene)
updateSelection.select("title").text(d => d.gene)
}
function adjacentlinks(nodes: Record<string, any>) {
const links = []
for (let i = 0; i < nodes.length; i++) {
if (i < nodes.length - 1) {
links.push({ index: i, source: nodes[i], target: nodes[+1] })
}
}
return links
}
</script>
<template>
<div ref="gbContainer">
......
......@@ -19,9 +19,17 @@ export interface StructureOperonGeneWithImg extends StructureOperonGene {
export interface StructureOperonGeneWithCoordinate extends StructureOperonGeneWithImg {
width: number
height: number
x: number | undefined
y: number | undefined
x: number
y: number
}
export interface StructureGeneLinks {
source: [number, number]
target: [number, number]
highlight: boolean
}
export type StructurePredictionType = "monomer" | "multimer" | "multimer(dimer)" | "multimer(homodimer)"
export type StructureType = "Validated" | "DF" | "na"
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment