Skip to content

Commit

Permalink
foldmason: replace tooltip with selection in structure and MSA
Browse files Browse the repository at this point in the history
  • Loading branch information
milot-mirdita committed Jan 15, 2025
1 parent 802fc72 commit 5f841da
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 10 deletions.
4 changes: 4 additions & 0 deletions frontend/MSA.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
:reference="structureViewerReference"
:mask="mask"
@loadingChange="handleStructureLoadingChange"
@columnSelected="selectedColumn = $event"
/>
</div>
<v-card-text v-else>
Expand Down Expand Up @@ -144,6 +145,8 @@
:selectedStructures="structureViewerSelection"
:referenceStructure="structureViewerReference"
:matchRatio="parseFloat(matchRatio)"
:mask="mask"
:highlightColumn="selectedColumn"
@cssGradients="handleCSSGradient"
@lineLen="handleLineLen"
@newStructureSelection="handleNewStructureViewerSelection"
Expand Down Expand Up @@ -253,6 +256,7 @@ export default {
isLoadingStructure: false,
numMinimapGradients: 30,
settingsPanelOpen: true,
selectedColumn: -1,
}
},
watch: {
Expand Down
37 changes: 31 additions & 6 deletions frontend/MSAView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@click="handleClickHeader($event, j)"
>{{ name }}</span>
<div class="sequence-wrapper">
<span class="sequence" :style="css">{{ alphabet === 'aa' ? aa : ss }}</span>
<span class="sequence" :style="css" v-html="insertHighlight(alphabet === 'aa' ? aa : ss, start, end)"></span>
</div>
<span class="count">{{ countSequence(aa, seqStart).toString() }}</span>
</template>
Expand Down Expand Up @@ -86,7 +86,6 @@ export default {
components: { SequenceLogo, SequenceLogo },
data() {
return {
mask: [],
lineLen: 80,
headerLen: null,
countLen: null,
Expand All @@ -99,10 +98,12 @@ export default {
scores: Array,
alnLen: Number,
alphabet: String,
mask: { type: Array },
selectedStructures: { type: Array, required: false },
referenceStructure: { type: Number },
colorScheme: { type: String, default: 'lddt' },
maxHeaderWidth: { type: Number, default: 30 }
maxHeaderWidth: { type: Number, default: 30 },
highlightColumn: { type: Number, default: -1 },
},
mounted() {
this.resizeObserver = new ResizeObserver(debounce(this.handleResize, 100)).observe(this.$refs.msaWrapper);
Expand All @@ -127,6 +128,18 @@ export default {
},
},
computed: {
maskCumSum() {
if (!this.mask) {
return [];
}
const result = [];
let sum = 0;
for (let i = 0; i < this.mask.length; i++) {
sum += this.mask[i] == 0;
result.push(sum);
}
return result;
},
firstSequenceWidth() {
const container = document.querySelector(".msa-block");
if (!container)
Expand Down Expand Up @@ -242,6 +255,18 @@ export default {
}
return result;
},
insertHighlight(seq, start, end) {
if (this.highlightColumn == -1 || this.mask[this.highlightColumn] == 0) {
return seq;
}
let column = this.highlightColumn - this.maskCumSum[this.highlightColumn];
if (column >= start && column < end) {
let idx = column - start;
let newseq = seq.substring(0, idx) + '<strong>' + seq.substring(idx, idx + 1) + '</strong>' + seq.substring(idx + 1);
return newseq;
}
return seq;
},
getEntryRanges(start, end, makeGradients=true) {
return Array.from(this.entries, entry => this.getEntryRange(entry, start, end, makeGradients));
},
Expand Down Expand Up @@ -325,9 +350,9 @@ export default {
color: transparent;
z-index: 0;
}
.msa-block .sequence::selection {
background: rgba(100, 100, 255, 1);
color: white;
.msa-block .sequence::selection, .msa-block .sequence strong {
background: #11FFEE;
color: #111;
}
.msa-row {
display: contents;
Expand Down
76 changes: 72 additions & 4 deletions frontend/StructureViewerMSA.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
disableTargetButton
style="position: absolute; bottom: 8px;"
/>
<div class="structure-viewer" ref="viewport" />
<div class="structure-viewer" ref="viewport"></div>
</div>
</div>
</template>
Expand Down Expand Up @@ -100,6 +100,29 @@ function getMaskedPositions(seq, mask) {
return result;
}
function getAlignmentPos(seq, residueIndex) {
let resno = -1;
for (let i = 0; i < seq.length; i++) {
if (seq[i] !== '-') {
resno++;
}
if (resno == residueIndex) {
return i;
}
}
return -1;
}
function getResidueIndex(seq, alignmentPos) {
let residueIndex = -1;
for (let i = 0; i <= alignmentPos && i < seq.length; i++) {
if (seq[i] !== '-') {
residueIndex++;
}
}
return residueIndex;
}
export default {
name: "StructureViewerMSA",
components: {
Expand All @@ -112,11 +135,12 @@ export default {
data: () => ({
structures: [], // { name, aa, 3di (ss), ca, NGL structure, alignment, map }
curReferenceIndex: -1, // index in ALL sequences, not just visualised subset - used as key,
schemeId: null, // NGL colorscheme
schemeId: null, // NGL colorscheme,
selectedColumn: -1,
}),
props: {
entries: { type: Array, required: true },
selection: { type: Array, required: true },
selection: { type: Array, required: true, default: [0, 1] },
mask: { type: Array, required: true },
reference: { type: Number, required: true },
bgColorLight: { type: String, default: "white" },
Expand All @@ -131,6 +155,31 @@ export default {
default: () => ({ color: 0xFFC107, opacity: 0.5, side: 'front' })
},
},
mounted() {
this.updateEntries(this.selection, []);
this.stage.signals.clicked.add((pickingProxy) => {
if (!pickingProxy) {
this.selectedColumn = -1;
this.updateMask()
this.$emit('columnSelected', -1);
return;
}
let atom = pickingProxy.atom;
if (!atom) {
this.selectedColumn = -1;
this.updateMask()
this.$emit('columnSelected', -1);
return;
}
let index = parseInt(atom.structure.name.replace("key-", ""));
let alnPos = getAlignmentPos(this.entries[index].aa, atom.residueIndex);
// console.log(atom.residueIndex, alnPos);
this.selectedColumn = alnPos;
this.$emit('columnSelected', alnPos);
this.updateMask()
});
},
methods: {
resetView() {
if (!this.stage) return;
Expand Down Expand Up @@ -269,7 +318,11 @@ ENDMDL
color = that.referenceStyleParameters.color;
}
let residueMask = getMaskedPositions(that.entries[index].aa, that.mask);
let highlightedIndex = getResidueIndex(that.entries[index].aa, that.selectedColumn);
this.atomColor = (atom) => {
if (highlightedIndex == atom.residueIndex) {
return 0x11FFEE;
}
if (residueMask.includes(atom.residueIndex)) {
return 0x666666;
}
Expand Down Expand Up @@ -363,12 +416,13 @@ ENDMDL
representation.setVisibility(true);
})
);
this.updateMask();
},
async updateMask() {
this.stage.eachRepresentation((repr) => {
repr.build();
});
}
},
},
watch: {
'$vuetify.theme.dark': function() {
Expand All @@ -388,6 +442,20 @@ ENDMDL
ambientIntensity() {
this.$vuetify.theme.dark ? 0.4 : 0.2;
},
stageParameters: function() {
return {
log: 'none',
backgroundColor: this.bgColor,
transparent: true,
ambientIntensity: this.ambientIntensity,
clipNear: -1000,
clipFar: 1000,
fogFar: 1000,
fogNear: -1000,
quality: 'high',
tooltip: false,
}
}
},
}
</script>
Expand Down

0 comments on commit 5f841da

Please sign in to comment.