웹 프로그래밍에는 아직 입문 단계라 좀 서투르게 작업할 수 있어요. 저는 HTML, CSS 및 자바스크립트를 사용하여 다양한 DNA 서열을 시각화하고 있습니다. 각 서열은 HTML 요소의 그래프로 표현되며 DNA 서열의 길이에 해당하는 고정 길이를 갖고 있어요. 각 그래프에서 일부 모티프를 나타내기 위해 고정 지점에 Span이 배치되어 있어요. 웹 프레임워크로는 Django를 사용하고 있어요.
이렇게 하여 여러 서열을 웹페이지에 한 줄씩 만들어 나가고 있어요. 지금 이 서열 중 일부는 서로 유사할 수 있어요. 아래에 표시된 서열과 유사한 부분을 시각적으로 나타내고 싶어요. 위와 같이 작업하고 있어요.
<div class="graph" style='--graph-length: {sequence_length}'>
<hr class="line">
{ for key, value2 in value.items }
{ if value2.start_position }
<span class='motif' style="--start: { value2.start_position }; --stop: { value2.stop_position };"></span>
{ endif }
{ endfor }
</div>
이렇게 함으로써 웹페이지에 여러 서열을 나란히 표시하고 있어요. 요청하신 그림처럼 아래에 표시된 서열과 유사한 영역을 시각화하여 표시하기 위해 노력하고 있어요. 부족한 부분이 있을 수 있지만 노력하고 있습니다.
위 예제에서 그래프1과 2, 그리고 그래프2와 3에 의해 표현되는 시퀀스는 유사한 영역을 가지고 있지만 시퀀스의 총 길이(따라서 그래프에 표시된 모티프의 크기)가 다르기 때문에 그래프2와 3 사이의 넓은 파란 요소가 발생합니다.
각 그래프에 대한 것은 각 그래프가 표현해야 하는 시퀀스의 길이, 해당 그래프의 모티프의 시작 및 끝 위치, 그리고 두 그래프(시퀀스)가 유사한 영역(그림에서 녹색)을 포함하는 경우 각 그래프에서의 유사한 영역의 시작 및 끝 위치입니다.
그래서 제 질문은: 두 그래프 사이의 유사한 영역을 나타내는 요소(그림에서 파란색)를 HTML, CSS 또는 JavaScript를 사용하여 어떻게 생성할 수 있을까요? (또는 이미 갖고 있는 것에 구현할 수 있는 다른 모든 것)
어떻게 접근할 수 있는지에 대한 힌트는 언제든지 환영이며, 궁금한 점이 있다면 알려주세요!
수정: 실제로 제 응용 프로그램에 통합하기에 더 적합하다고 생각하기 때문에 부탁드립니다.
해결책
SVG를 사용하거나 캔버스를 사용할 수 있습니다.
여기 캔버스로의 미니멀한 접근 방식이 있습니다. 아마도 귀하의 것과 유사한 다이어그램을 제공할 가능성이 매우 높은 라이브러리에 의존하는 것이 좋을 것입니다.
하지만 긁는 것은 결코 아프지 않아요.
아래에서, 각 그래프는 축을 적절하게 조정하는 것이 책임이에요.
마침내, 사다리꼴은 해당하는 꼭지점들의 크기를 조정하기 위해 의존하는 그래프에 의존해요.
텍스트를 더 조건적으로 표시하려면 Bar와 함께 노는 게 좋아하며 표시할지 여부를 나타내는 부울 값을 제공할 수 있어요.
캔버스의 스타일을 선의 굵기 등으로 더 창의적으로 꾸밀 수도 있지만, 그저 여러분이 쉽게 설정할 수 있다는 데모예요.
const canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
let bars = [
[Bar(200, 300), Bar(1800,2300), Bar(2500, 4500), Bar(5000,5200), Bar(8000,8500)],
[Bar(1100,1300), Bar(3000, 3800), Bar(4000, 4200), Bar(7000, 7500)],
[Bar(1, 2700)]
]
function Bar(a,b){return [a, b]}
class Graph{
constructor ({anchorY, width, min, max}) {
this.anchorY = anchorY
this.width = width
this.dw = width / (max - min )
this.min = min
this.max = max
}
plot (bars) {
// plot bars
// resize bars dimension to fit canvas
const e = 5
ctx.fillStyle = 'orange'
const scaledBars = bars.map(([a, b]) => [ a, b, a * this.dw, b * this.dw ])
scaledBars.forEach(([_, dum, left, right])=>{
ctx.fillRect(left, this.anchorY - e, right - left, 2*e)
})
// plot line
ctx.strokeStyle = 'black'
ctx.beginPath()
ctx.moveTo(0, this.anchorY)
ctx.lineTo(this.width, this.anchorY)
ctx.closePath()
ctx.stroke()
ctx.strokeStyle = 'green'
ctx.font = '10px serif'
scaledBars.forEach(([origLeft, origRight, left, right]) => {
ctx.strokeText(origLeft, left, this.anchorY - 10)
if (right - left > 100 ) {
ctx.strokeText(origRight, right, this.anchorY - 10)
}
})
}
//x will be shifted automatically
moveTo (x) {
ctx.moveTo(x * this.dw, this.anchorY)
}
lineTo (x) {
ctx.lineTo(x * this.dw, this.anchorY)
}
}
const graphs = [
new Graph({anchorY:100, width: canvas.width, min: 1, max: 10000}),
new Graph({anchorY:200, width: canvas.width, min: 1, max: 8500}),
new Graph({anchorY:300, width: canvas.width, min: 1, max: 4000})
]
// g first graph, (a,b) left, right anchors in first graph
// g2 second graph, c right anchor, d left anchor in second graph
function trapeze(g, a, b, g2, c, d){
ctx.beginPath()
g.moveTo(a)
g.lineTo(b)
g2.lineTo(c)
g2.lineTo(d)
ctx.closePath()
ctx.fillStyle = 'rgba(84, 147, 158, 0.5)'
ctx.fill()
}
const [g1, g2, g3] = graphs
const trapezes = [
[g1, 1800, 4500, g2, 3800, 1100],
[g1, 8000, 8500, g2, 7500, 7000],
[g2, 1100, 3800, g3, 2700, 1],
]
trapezes.forEach(t => trapeze(...t))
graphs.forEach((g, i) => {
g.plot(bars[i])
})
canvas{background:#eeeeee;}
<canvas width="400" height="400"></canvas>
이 답변은 stackoverflow에서 수집한 것이며, cc by-sa 2.5, cc by-sa 3.0 및 cc by-sa 4.0으로 라이센스가 부여되어 있습니다.