gosling-lang / gosling.js

Grammar of Scalable Linked Interactive Nucleotide Graphics
https://gosling.js.org
MIT License
166 stars 27 forks source link

Performance roadmap: reducing redraws and reducing GoslingTrackModel initializations #1036

Open etowahadams opened 9 months ago

etowahadams commented 9 months ago

The frame-rate of certain Gosling visualizations is very low when zooming and panning. What are the main bottlenecks?

Flame charts

We can interact with laggy visualzations and observe their flame charts to understand what is causing poor performance.

Multiple Sequence Alignment

{"zoomLimits": [1, 396],"xDomain": {"interval": [350, 396]},"assembly": "unknown","views": [{"tracks": [{"alignment": "overlay","data": {"url": "https://raw.githubusercontent.com/sehilyi/gemini-datasets/master/data/alignment_viewer_p53.fasta.csv","type": "csv","genomicFields": ["pos"],"sampleLength": 99999},"tracks": [{"mark": "rect"},{"mark": "text","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"color": {"value": "black"},"size": {"value": 12},"visibility": [{"measure": "zoomLevel","target": "track","threshold": 10,"operation": "LT","transitionPadding": 100}]}],"x": {"field": "pos", "type": "genomic", "axis": "none"},"row": {"field": "name", "type": "nominal", "legend": false},"color": {"field": "base","type": "nominal","range": ["#d60000","#018700","#b500ff","#05acc6","#97ff00","#ffa52f","#ff8ec8","#79525e","#00fdcf","#afa5ff","#93ac83","#9a6900","#366962","#d3008c","#fdf490","#c86e66","#9ee2ff","#00c846","#a877ac","#b8ba01"],"legend": false},"stroke": {"value": "white"},"strokeWidth": {"value": 0},"text": {"field": "base", "type": "nominal"},"width": 800,"height": 400,"title": "Original Approach"}]}]}

Here's a flame graph when zooming in and out of :

image

SARS-Cov2

{"title": "SARS-CoV-2","subtitle": "Data Source: WashU Virus Genome Browser, NCBI, GISAID","assembly": [["NC_045512.2", 29903]],"layout": "linear","spacing": 50,"views": [{"alignment": "overlay","title": "NC_045512.2 Genes","data": {"type": "csv","url": "https://s3.amazonaws.com/gosling-lang.org/data/COVID/NC_045512.2-Genes.csv","chromosomeField": "Accession","genomicFields": ["Start", "Stop"]},"tracks": [{"mark": "rect","color": {"value": "#0072B2"},"stroke": {"value": "white"},"strokeWidth": {"value": 2}},{"mark": "rule","color": {"value": "white"},"opacity": {"value": 0.6},"strokeWidth": {"value": 0},"style": {"linePattern": {"type": "triangleRight", "size": 10}}},{"mark": "text","text": {"field": "Gene symbol", "type": "nominal"},"color": {"value": "black"},"stroke": {"value": "white"},"strokeWidth": {"value": 3},"visibility": [{"target": "mark","measure": "width","threshold": "|xe-x|","operation": "LTET","transitionPadding": 30}]},{"mark": "brush", "x": {"linkingId": "detail"}}],"x": {"field": "Start", "type": "genomic"},"xe": {"field": "Stop", "type": "genomic"},"width": 800,"height": 30,"static": true,"layout": "linear","xDomain": {"interval": [1, 29903]}},{"centerRadius": 0,"xDomain": {"interval": [1, 29903]},"linkingId": "detail","alignment": "stack","tracks": [{"alignment": "overlay","title": "S Protein Annotation","data": {"type": "csv","url": "https://s3.amazonaws.com/gosling-lang.org/data/COVID/sars-cov-2_Sprot_annot_sorted.bed","chromosomeField": "Accession","genomicFields": ["Start", "Stop"]},"tracks": [{"mark": "rect","color": {"field": "Protein","type": "nominal","domain": ["receptor-binding domain (RBD)","receptor-binding motif (RBM)","S1/S2 cleavage site","heptad repeat 1 (HR1)","heptad repeat 2 (HR2)"]},"xe": {"field": "Stop", "type": "genomic"}},{"mark": "text","text": {"field": "Protein", "type": "nominal"},"color": {"value": "#333"},"stroke": {"value": "white"},"strokeWidth": {"value": 3},"style": {"textAnchor": "end"}}],"x": {"field": "Start", "type": "genomic"},"row": {"field": "Protein","type": "nominal","domain": ["receptor-binding domain (RBD)","receptor-binding motif (RBM)","S1/S2 cleavage site","heptad repeat 1 (HR1)","heptad repeat 2 (HR2)"]},"width": 800,"height": 80},{"alignment": "overlay","title": "NC_045512.2 Genes","data": {"type": "csv","url": "https://s3.amazonaws.com/gosling-lang.org/data/COVID/NC_045512.2-Genes.csv","chromosomeField": "Accession","genomicFields": ["Start", "Stop"]},"tracks": [{"mark": "rect","color": {"value": "#0072B2"},"stroke": {"value": "white"},"strokeWidth": {"value": 2}},{"mark": "rule","color": {"value": "white"},"opacity": {"value": 0.6},"strokeWidth": {"value": 0},"style": {"linePattern": {"type": "triangleRight", "size": 10}}},{"mark": "text","text": {"field": "Gene symbol", "type": "nominal"},"color": {"value": "black"},"stroke": {"value": "white"},"strokeWidth": {"value": 3},"visibility": [{"target": "mark","measure": "width","threshold": "|xe-x|","operation": "LTET","transitionPadding": 30}]}],"x": {"field": "Start", "type": "genomic"},"xe": {"field": "Stop", "type": "genomic"},"width": 800,"height": 30},{"title": "NC_045512.2 Sequence","alignment": "overlay","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=NC_045512_2-multivec","type": "multivec","row": "base","column": "position","value": "count","categories": ["A", "T", "G", "C"],"start": "start","end": "end"},"tracks": [{"mark": "bar","y": {"field": "count", "type": "quantitative", "axis": "none"}},{"dataTransform": [{"type": "filter", "field": "count", "oneOf": [0], "not": true}],"mark": "text","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"size": {"value": 24},"color": {"value": "white"},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 30,"target": "mark"},{"operation": "LT","measure": "zoomLevel","threshold": 40,"target": "track"}]}],"x": {"field": "position", "type": "genomic"},"color": {"field": "base","type": "nominal","domain": ["A", "T", "G", "C"],"legend": true},"text": {"field": "base", "type": "nominal"},"style": {"inlineLegend": true},"width": 800,"height": 40},{"title": "TRS-L-Dependent Recombination Events","data": {"type": "csv","url": "https://s3.amazonaws.com/gosling-lang.org/data/COVID/TRS-L-dependent_recombinationEvents_sorted.bed","chromosomeField": "Accession","genomicFields": ["Start1", "Stop1", "Start2", "Stop2"],"sampleLength": 100},"mark": "withinLink","x": {"field": "Start1", "type": "genomic"},"xe": {"field": "Stop1", "type": "genomic"},"x1": {"field": "Start2", "type": "genomic"},"x1e": {"field": "Stop2", "type": "genomic"},"stroke": {"value": "#0072B2"},"color": {"value": "#0072B2"},"opacity": {"value": 0.1},"width": 800,"height": 400}]}]}
image

Corces et al.

{"title": "Single-cell Epigenomic Analysis","subtitle": "Corces et al. 2020","layout": "linear","arrangement": "vertical","views": [{"layout": "linear","xDomain": {"chromosome": "chr3"},"centerRadius": 0.8,"tracks": [{"alignment": "overlay","title": "chr3","data": {"url": "https://raw.githubusercontent.com/sehilyi/gemini-datasets/master/data/cytogenetic_band.csv","type": "csv","chromosomeField": "Chr.","genomicFields": ["ISCN_start","ISCN_stop","Basepair_start","Basepair_stop"]},"tracks": [{"mark": "rect","dataTransform": [{"type": "filter","field": "Stain","oneOf": ["acen-1", "acen-2"],"not": true}],"color": {"field": "Density","type": "nominal","domain": ["", "25", "50", "75", "100"],"range": ["white", "#D9D9D9", "#979797", "#636363", "black"]},"size": {"value": 20}},{"mark": "rect","dataTransform": [{"type": "filter", "field": "Stain", "oneOf": ["gvar"]}],"color": {"value": "#A0A0F2"},"size": {"value": 20}},{"mark": "triangleRight","dataTransform": [{"type": "filter", "field": "Stain", "oneOf": ["acen-1"]}],"color": {"value": "#B40101"},"size": {"value": 20}},{"mark": "triangleLeft","dataTransform": [{"type": "filter", "field": "Stain", "oneOf": ["acen-2"]}],"color": {"value": "#B40101"},"size": {"value": 20}},{"mark": "brush","x": {"linkingId": "detail"},"color": {"value": "red"},"opacity": {"value": 0.3},"strokeWidth": {"value": 1},"stroke": {"value": "red"}}],"x": {"field": "Basepair_start", "type": "genomic", "axis": "none"},"xe": {"field": "Basepair_stop", "type": "genomic"},"stroke": {"value": "black"},"strokeWidth": {"value": 1},"style": {"outlineWidth": 0},"width": 400,"height": 25}]},{"xDomain": {"chromosome": "chr3", "interval": [52168000, 52890000]},"linkingId": "detail","x": {"field": "position", "type": "genomic"},"y": {"field": "peak", "type": "quantitative", "axis": "right"},"style": {"outline": "#20102F"},"width": 400,"height": 40,"tracks": [{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/ExcitatoryNeurons-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Excitatory neurons","mark": "bar","color": {"value": "#F29B67"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/InhibitoryNeurons-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Inhibitory neurons","mark": "bar","color": {"value": "#3DC491"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/DopaNeurons_Cluster10_AllFrags_projSUNI2_insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Dopaminergic neurons","mark": "bar","color": {"value": "#565C8B"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/Microglia-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Microglia","mark": "bar","color": {"value": "#77C0FA"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/Oligodendrocytes-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Oligodendrocytes","mark": "bar","color": {"value": "#9B46E5"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/Astrocytes-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "Astrocytes","mark": "bar","color": {"value": "#D73636"}},{"data": {"url": "https://s3.amazonaws.com/gosling-lang.org/data/OPCs-insertions_bin100_RIPnorm.bw","type": "bigwig","column": "position","value": "peak"},"title": "OPCs","mark": "bar","color": {"value": "#E38ADC"}},{"alignment": "overlay","title": "Genes","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"style": {"outline": "#20102F"},"tracks": [{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "text","text": {"field": "name", "type": "nominal"},"x": {"field": "start", "type": "genomic"},"size": {"value": 8},"xe": {"field": "end", "type": "genomic"},"style": {"textFontSize": 8, "dy": -12}},{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "text","text": {"field": "name", "type": "nominal"},"x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"size": {"value": 8},"style": {"textFontSize": 8, "dy": 10}},{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "rect","x": {"field": "end", "type": "genomic"},"size": {"value": 7}},{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "rect","x": {"field": "start", "type": "genomic"},"size": {"value": 7}},{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["exon"]}],"mark": "rect","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"size": {"value": 14}},{"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]}],"mark": "rule","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"strokeWidth": {"value": 3}}],"row": {"field": "strand", "type": "nominal", "domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#012DB8", "#BE1E2C"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"width": 400,"height": 80},{"title": "PLAC-seq (H3K4me3) Nott et al.","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=oligodendrocyte-plac-seq-bedpe","type": "beddb","genomicFields": [{"name": "start", "index": 1},{"name": "end", "index": 2}]},"mark": "withinLink","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"y": {"flip": true},"strokeWidth": {"value": 1},"color": {"value": "none"},"stroke": {"value": "#F97E2A"},"opacity": {"value": 0.1},"overlayOnPreviousTrack": false,"width": 400,"height": 60},{"title": "","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=microglia-plac-seq-bedpe","type": "beddb","genomicFields": [{"name": "start", "index": 1},{"name": "end", "index": 2}]},"mark": "withinLink","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"y": {"flip": true},"strokeWidth": {"value": 1},"color": {"value": "none"},"stroke": {"value": "#50ADF9"},"opacity": {"value": 0.1},"overlayOnPreviousTrack": true,"width": 400,"height": 60},{"title": "","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=neuron-plac-seq-bedpe","type": "beddb","genomicFields": [{"name": "start", "index": 1},{"name": "end", "index": 2}]},"mark": "withinLink","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"y": {"flip": true},"strokeWidth": {"value": 1},"color": {"value": "none"},"stroke": {"value": "#7B0EDC"},"opacity": {"value": 0.1},"overlayOnPreviousTrack": true,"width": 400,"height": 60}]}]}
image

Mark Displacement

{"title": "Mark Displacement","subtitle": "Reposition marks to address visual overlaps using displacement options","spacing": 1,"centerRadius": 0.8,"xDomain": {"chromosome": "chr17", "interval": [43080000, 43120000]},"views": [{"alignment": "overlay","xDomain": {"chromosome": "chr3", "interval": [142500000, 143000000]},"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=transcript-hg38-beddb","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 0, "name": "chr", "type": "nominal"},{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"},{"index": 9, "name": "exon_start", "type": "nominal"},{"index": 10, "name": "exon_end", "type": "nominal"}]},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15}],"title": "hg38 | Transcript (Max. 15 Rows)","tracks": [{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "triangleRight","x": {"field": "end", "type": "genomic", "axis": "top"},"size": {"value": 15}},{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "filter", "field": "type", "oneOf": ["gene"]}],"mark": "text","text": {"field": "name", "type": "nominal"},"x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"style": {"dy": -10}},{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "triangleLeft","x": {"field": "start", "type": "genomic"},"size": {"value": 15},"style": {"align": "right"}},{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "exonSplit","separator": ",","flag": {"field": "type", "value": "exon"},"fields": [{"field": "exon_start","type": "genomic","newField": "start","chrField": "chr"},{"field": "exon_end","type": "genomic","newField": "end","chrField": "chr"}]},{"type": "filter", "field": "type", "oneOf": ["exon"]}],"mark": "rect","size": {"value": 10},"x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"}},{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "rule","x": {"field": "start", "type": "genomic"},"strokeWidth": {"value": 3},"xe": {"field": "end", "type": "genomic"},"style": {"linePattern": {"type": "triangleRight", "size": 5}}},{"dataTransform": [{"type": "displace","method": "pile","boundingBox": {"startField": "start", "endField": "end"},"newField": "row","maxRows": 15},{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "rule","x": {"field": "start", "type": "genomic"},"strokeWidth": {"value": 3},"xe": {"field": "end", "type": "genomic"},"style": {"linePattern": {"type": "triangleRight", "size": 5}}}],"row": {"field": "row", "type": "nominal"},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#0072B2", "#D45E00"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"style": {"outline": "black"},"width": 700,"height": 500},{"xDomain": {"chromosome": "chr2", "interval": [126800000, 127700000]},"tracks": [{"alignment": "overlay","title": "Likely Benign","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=clinvar-beddb","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 7, "name": "significance", "type": "nominal"},{"type": "nominal", "index": 3, "name": "3"},{"type": "nominal", "index": 4, "name": "4"}]},"dataTransform": [{"type": "filter","field": "significance","oneOf": ["Likely_benign"]},{"type": "displace","boundingBox": {"startField": "start","endField": "end","padding": 5},"method": "spread","newField": "a"}],"tracks": [{"mark": "point","size": {"value": 4},"color": {"value": "#029F73"},"stroke": {"value": "black"},"strokeWidth": {"value": 1}},{"mark": "text","color": {"field": "3","type": "nominal","domain": ["A", "T", "G", "C"],"legend": true},"text": {"field": "3", "type": "nominal"},"y": {"value": 48}},{"mark": "text","color": {"field": "4","type": "nominal","domain": ["A", "T", "G", "C"]},"text": {"field": "4", "type": "nominal"},"y": {"value": 18}},{"mark": "text","color": {"value": "gray"},"text": {"value": "↓"},"y": {"value": 33}}],"x": {"field": "aStart", "type": "genomic"},"xe": {"field": "aEnd", "type": "genomic"},"y": {"value": 5},"opacity": {"value": 0.8},"style": {"inlineLegend": true},"width": 700,"height": 60},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=clinvar-beddb","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 7, "name": "significance", "type": "nominal"}]},"dataTransform": [{"type": "filter","field": "significance","oneOf": ["Likely_benign"]},{"type": "displace","boundingBox": {"startField": "start","endField": "end","padding": 5},"method": "spread","newField": "a"}],"mark": "betweenLink","xe": {"field": "start", "type": "genomic"},"x": {"field": "aStart", "type": "genomic"},"color": {"value": "#029F73"},"stroke": {"value": "lightgrey"},"strokeWidth": {"value": 0.5},"opacity": {"value": 0.8},"width": 700,"height": 60},{"alignment": "overlay","tracks": [{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=clinvar-beddb","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 7, "name": "significance", "type": "nominal"}]},"dataTransform": [{"type": "filter","field": "significance","oneOf": ["Likely_benign"]}],"mark": "rect","color": {"value": "lightgray"},"stroke": {"value": "lightgray"},"strokeWidth": {"value": 0.5},"x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"opacity": {"value": 0.8}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "triangleRight","x": {"field": "end", "type": "genomic", "axis": "none"},"size": {"value": 15}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]}],"mark": "text","text": {"field": "name", "type": "nominal"},"x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"style": {"dy": -15}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "triangleLeft","x": {"field": "start", "type": "genomic"},"size": {"value": 15},"style": {"align": "right"}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["exon"]}],"mark": "rect","x": {"field": "start", "type": "genomic"},"size": {"value": 15},"xe": {"field": "end", "type": "genomic"}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["+"]}],"mark": "rule","x": {"field": "start", "type": "genomic"},"strokeWidth": {"value": 3},"xe": {"field": "end", "type": "genomic"},"style": {"linePattern": {"type": "triangleRight", "size": 5}}},{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=gene-annotation","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 5, "name": "strand", "type": "nominal"},{"index": 3, "name": "name", "type": "nominal"}],"exonIntervalFields": [{"index": 12, "name": "start"},{"index": 13, "name": "end"}]},"row": {"field": "strand","type": "nominal","domain": ["+", "-"]},"color": {"field": "strand","type": "nominal","domain": ["+", "-"],"range": ["#7585FF", "#FF8A85"]},"visibility": [{"operation": "less-than","measure": "width","threshold": "|xe-x|","transitionPadding": 10,"target": "mark"}],"opacity": {"value": 0.8},"dataTransform": [{"type": "filter", "field": "type", "oneOf": ["gene"]},{"type": "filter", "field": "strand", "oneOf": ["-"]}],"mark": "rule","x": {"field": "start", "type": "genomic"},"strokeWidth": {"value": 3},"xe": {"field": "end", "type": "genomic"},"style": {"linePattern": {"type": "triangleLeft", "size": 5}}}],"width": 700,"height": 100}]},{"tracks": [{"data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=clinvar-beddb","type": "beddb","genomicFields": [{"index": 1, "name": "start"},{"index": 2, "name": "end"}],"valueFields": [{"index": 7, "name": "significance", "type": "nominal"}]},"displacement": {"type": "pile", "padding": 3.5},"mark": "point","x": {"field": "start", "type": "genomic"},"xe": {"field": "end", "type": "genomic"},"size": {"value": 3},"color": {"field": "significance","type": "nominal","domain": ["Pathogenic","Pathogenic/Likely_pathogenic","Likely_pathogenic","Uncertain_significance","Likely_benign","Benign/Likely_benign","Benign"],"range": ["#CB3B8C","#CB71A3","#CB96B3","gray","#029F73","#5A9F8C","#5A9F8C"],"legend": true},"width": 700,"height": 260}]}],"style": {"outlineWidth": 0}}
image

Observations

Based on the flame charts, we observe three main bottlenecks:

  1. Redrawing over and over
  2. Data transformations - converting a data into a form that that makes it ready to visualize. This involves use of
  3. Creating GoslingTrackModel over over again

Reduce redrawing

Redrawing everything to the same Graphics object is expensive. There are several strategies to overcome this

Initialize GoslingTrackModel only when needed

GoslingTrackModels are reinitialized every time draw() is called. However, it only changes when the data, spec, or theme changes. We need to persist the models unless the data, spec, or theme changes.

etowahadams commented 9 months ago

Optimizing the point mark: 4.2X speedup

Spec:

{"layout": "linear","arrangement": "vertical","centerRadius": 0.8,"xDomain": {"chromosome": "chr1", "interval": [1, 3000500]},"views": [{"tracks": [{"id": "track-6","data": {"url": "https://server.gosling-lang.org/api/v1/tileset_info/?d=cistrome-multivec","type": "multivec","row": "sample","column": "position","value": "peak","categories": ["sample 1", "sample 2", "sample 3", "sample 4"]},"mark": "point","x": {"field": "position", "type": "genomic", "axis": "top"},"y": {"field": "peak", "type": "quantitative", "grid": true},"size": {"field": "peak", "type": "quantitative"},"color": {"field": "sample", "type": "nominal", "legend": true},"opacity": {"value": 0.5},"tooltip": [{"field": "start", "type": "genomic", "alt": "Start Position"},{"field": "end", "type": "genomic", "alt": "End Position"},{"field": "peak","type": "quantitative","alt": "Value","format": ".2"},{"field": "sample", "type": "nominal", "alt": "Sample"}],"width": 600,"height": 130}]}]}
image

Stack charts

Before: 5.5 ms to draw a frame

image

After: 1.3 ms to draw, or a 4.2X speedup

image

Frame charts (firefox)

image

After

image

Changes:

How does draw time scale with the number of tracks?

Theoretically, it should take 1.3 ms to draw each track. Does draw time scale linearly with the number of tracks? Yes, but not with the relation that we want. Specifically, it draws 2x-1 times more than it needs to.

For example, here a visualization with 3 tracks. We expect each track to be drawn only once (3 total calls to draw) but instead we see 5.

image

Overall, this amounts in the following relationship:

image