Published
Edited
Aug 24, 2021
Insert cell
Insert cell
dashboard = html`
<div id='dashboard'>

<div style="display: flex;">
<div id="meta_dropdown", style="margin-right: 15px; border:1px; text-align:left;">${viewof select_gene_dropdown} </div>
<div style="margin-right: 15px; border:1px; text-align:left;">${viewof transcript_radius} </div>
<div style="margin-right: 15px; border:1px; text-align:left;">${viewof transcript_opacity} </div>
</div>
<div style="margin-top: 15px; flex-basis:50%; border:1px ">${container} </div>
</div>
`

Insert cell
select_gene
Insert cell
viewof select_gene_dropdown = select({'options':['none'].concat(Object.keys(gene_colors)), value: 'none'})
Insert cell
mutable select_gene = select_gene_dropdown
Insert cell
Insert cell
transcript_data.map(x => x.name).filter((v, i, a) => a.indexOf(v) === i)
Insert cell
gene_colors = ({
'Acsm3': 'black',
'Spp1': 'yellow'
})
Insert cell
transcript_data_ini = JSON.parse(decode_zipped_string(zip_string))
// transcript_data_ini = JSON.parse(tmp1)
Insert cell
// tmp1 = '[{"barcode_id": 0, "position": "[4827.31, 4176.69]", "color": "[206, 109, 189]"}, {"barcode_id": 0, "position": "[4698.01, 4148.36]", "color": "[206, 109, 189]"}, {"barcode_id": 0, "position": "[4809.01, 4196.75]", "color": "[206, 109, 189]"}, {"barcode_id": 0, "position": "[4753.14, 4080.71]", "color": "[206, 109, 189]"}, {"barcode_id": 0, "position": "[4748.22, 4159.53]", "color": "[206, 109, 189]"}, {"barcode_id": 0, "position": "[4746.27, 4101.38]", "color": "[206, 109, 189]"}, {"barcode_id": 1, "position": "[4702.77, 4186.85]", "color": "[214, 97, 107]"}, {"barcode_id": 1, "position": "[4724.2, 4154.57]", "color": "[214, 97, 107]"}, {"barcode_id": 1, "position": "[4790.28, 4141.16]", "color": "[214, 97, 107]"}, {"barcode_id": 1, "position": "[4795.07, 4138.86]", "color": "[214, 97, 107]"}]'

// tmp1 = 'eJytz00KwkAMhuGrDFkPIZmfTOIlPEDpQkSkoB2pLgTx7k6rK3dSN9m88PCle8ClXofbUEfYOOiShoKRvUtcBMV68A729VSnJQcS75isHX23cXc+zGl7P04MT+++QTFFWsCkGGU9qGQf0ARLXg+WHJFTA0kJC/8BbJ+GMC/Mhjn+CvYvDilm8Q=='

// working
// tmp1 = 'eJylz80KwjAMB/BXKT2X0KRNm3nzCXyAscP8YAzUShURxHe33cmJHsRDIORPfiTtXZ/SebyM6agXqo2RwYpRwRODSGeU3qR9yjUjh0ahBKOEanDsD7sy18vtkK+oH0a9WWIh+sly4MNfFtpI4MsO+9I4nGFNUyyqYXy1Vrchf6SEoZFKMQPTjMLojJrKz89Kuaf1l7tseZIZGYL8hHVPErtkQg=='

// not working
zip_string = 'eJyNmLuKpEcMhV+lmbgpVFLp5szP4HDZwBgHG+wF1pnxu/uoeliD7eAkQ88w6qpfl+8c/R/+fPvy6+ff3356vP382/fP9vZ8vH37+v3TH5++fsEfP+wIX773eT60e5Vp2se/no9/wn759m3/J8p3Lo2I5yPNV0o4E3RqedoNynW0mKBWXTkHlSau18ztYu+FB8Ez9Tlr21Em6Og6sRVB1fhUwTxS1RJ3xLStwBNSB/myUzfI1y4q3/h6FdnPx8bPZRVFHTVlKo8JC8XHSjJ9uW2CEhXzZmKk1pmMbylbZx/meolM7PQ5ae9eLlT+vGR13lxstSXKVDftoPf0HmW6DL8zUZLLuuaxNiodwqQv5Uz7TEzH2txABRo1/d5PkX6voCqVBzMRE3VclohvJsrRTGE3KnXtaGo+Cv9qGjcKXX+MSsa+LT7ZOKgb6lxMifEwmolZjJhPFFyQdT04KBLzBVBQ85uyXHsOypyxooiEK0kifSlo2lNMzl03gmYScx984sprhaaY5DV6Qo9TzxS4n2UMyDD+wZ6VwMq+zAQpDA1JTb2t2tqDssQkCpOKPrFK7oCITdczfMkYkumLZMN04e4HcWrpiyWBTiXHsr2ixG9UrUbnUmn3aaWLzT5gRVPJAIwS+jm0EBDaD0OLwgR3i15wCmrsjJTODdPMLzhBi91c5keuJC/PprOaysZGE/npGwU5UYpMQwvV2xq2ry+hziqMfvUIgoFnx5kpSUUQxmomv1ZBVChMA7ih9e4sDifCqKv10ZfeQ4cpbfTAlMRLuqdYlRwxRkbHxNwmBNCYtBfgZNFX5obXp5i0ZzRcVtwSO0ADxFFNuJdMCCqlQoUkvEGATVeFMcVGlWrgbH2vp8BMFcXp3AHx1elAzV4gFNWBSAVk4SpqwAjKoc7KOWuy7vAZIDYzxIlpgsLdKNQqkUMqytcBM2GjDYqHk6nGzYU+vHSH/NShgsa9mL4wCHJEUHMlYy76IreB3OTOwgXr3Qki7aSpC4W9t7rwhPzrTqrEcBVlc9SBfgmFpQTBLjiP+4qgzHcrvr2u80FKDvqRrZSNo4NuLW/n1BsbD/IwYMKhtTmj4OPvX+uLYztoo1Y/7C+e57VTBAafiopja3e9hBgbo3H+x2b7+yHEZzdlVGNDBfJCBtolydl2gA+27trbmK1RKYMBM2OSfq009hJuB8zABmKv1sCMJbfLQfOtxha3jeBRaXc8/76b8IhcUoQJiRWnc9bn8apKeenAUu/q74gR+DVqFEH2unMF036KqxRMApTjDjAIg22GaVsDzBMxOSEcyWx2o3mf0iCGqCW309YPe2sBv8VpAZxwyc3ERAXp9HfBmuX132gpaaN6Fog4r119omCqqbME3qr0vhdApws59/AI2EyvH8EXSG0mhw1Hp3WVEd+AYzflR+YdRNd1MSATFgsq8/MqS+8A+x7r86/W+P93bTnZ6Gv2BRvu4cy+yABTUC9DvTO4cdQamzXMOE5BCR5/Hew7zwdEBzsJ14CjNtfaghmuwVwNNVptck0+0qjMgLQ3hHoiANwjk+6PfwObvn3a'
Insert cell
// number_of_genes = Object.keys(unzip_json).length
Insert cell
// unzip_json = JSON.parse(decode_zipped_string(zip_string))
Insert cell
// zip_string = 'eJyrVspLLdfNTq1UslIAM8sSc0pTlWoBZN4ILw=='
Insert cell
pako = require('pako/dist/pako.min.js')
Insert cell
container = html `<div style="height:${height}px; border-style:solid; border-color:#d3d3d3; border-width:1px"></div>`
Insert cell
Insert cell
transcript_data = transcript_data_ini.map(d => {

var inst_color_name = gene_colors[d.name]
var rgb = d3.color(inst_color_name)
var inst_color = [rgb.r, rgb.g, rgb.b] // 255

var new_obj = ({
'': d[''],
'name': d.name,
'position': eval(d.position),
'color': inst_color
})
return new_obj
})

// transcript_data = transcript_data_ini
Insert cell
Insert cell
radius = 0.5
Insert cell
radius_min_pixels = 1.5
Insert cell
transitionDuration = 3000
Insert cell
transitions = ({
getPosition: {
duration:transitionDuration,
easing: d3.easeCubic
}
})
Insert cell
rgb = d3.color('red')
Insert cell
inst_color = [rgb.r, rgb.g, rgb.b, 255]
Insert cell
Object.keys(gene_colors)
Insert cell
select_gene
Insert cell
transcript_layer = new deck.ScatterplotLayer({
id: 'transcript_layer',
data: transcript_data,
pickable: is_pickable,
getPosition: d => d.position,

getFillColor: d => {
var inst_color
var unselected_color = [0, 0, 0, 0]
// allow transcript color filtering
if (select_gene === 'none'){
inst_color = d.color
} else {
inst_color = unselected_color
// check gene name
if (d.name === select_gene){
inst_color = d.color

}
}
return inst_color
},
getRadius: transcript_radius,
radiusMinPixels: transcript_radius,
pickable: true,
opacity: transcript_opacity,
visible: visible_transcripts,
updateTriggers: {
getFillColor: select_gene,
},
onClick: (info, event) => {
if (select_gene !== info.object.name){
mutable select_gene = info.object.name
d3.select('#meta_dropdown').select('select').node().value = info.object.name
} else {
mutable select_gene = 'none'
d3.select('#meta_dropdown').select('select').node().value = 'none'
}
}
})
Insert cell
mutable visible_transcripts = true
Insert cell
select_gene
Insert cell
// mutable select_gene = 'none'
Insert cell
layers = [transcript_layer]
Insert cell
is_pickable = true
Insert cell
deckgl.setProps({layers: layers});
Insert cell
view = new deck.OrthographicView({id: 'ortho'})
Insert cell
function ini_deckgl(container){
var deckgl =
new deck.DeckGL({
container,
views:[view],
initialViewState: initial_view_state,
controller: {doubleClickZoom: false},
// getTooltip: ({object}) => {
// return object &&
// `${object['name']}`
// // `pos: ${object.x}, ${object['y']}\n`
// },
getTooltip: ({object}) => object && {
html: `${object.name}`,
style: {
fontSize: '0.8em',
padding: '5px',
}
},
// onViewStateChange: ({viewState}) => {
// debounced_something(viewState)
// return viewState
// },
// onClick: ({info}) => {
// console.log(info)
// return info
// }
});
return deckgl
}
Insert cell
deckgl = ini_deckgl(container)
Insert cell
// d3.max(transcript_data,
mean_x = d3.mean(transcript_data.map(x => x['position'][0]))
Insert cell
mean_y = d3.mean(transcript_data.map(x => x['position'][1]))
Insert cell
min_zoom = -5
Insert cell
initial_view_state = ({
target: [mean_x, mean_y, 0],
zoom: -3.5,
minZoom: min_zoom,
maxZoom:10
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
height = 800
Insert cell
Insert cell
detail_zoom_thresh = 1.25
Insert cell
visible_transcripts
Insert cell
mutable fovs = []
Insert cell
function decode_zipped_string(b64Data){
// Get some base64 encoded binary data from the server. Imagine we got this:
// Decode base64 (convert ascii to binary)
var strData = atob(b64Data);
// Convert binary string to character-number array
var charData = strData.split('').map(function(x){return x.charCodeAt(0);});
// Turn number array into byte-array
var binData = new Uint8Array(charData);
// Pako magic
var data = pako.inflate(binData);
// // Convert gunzipped byteArray back to ascii string:
// var strData = String.fromCharCode.apply(null, new Uint16Array(data));

// https://stackoverflow.com/questions/8936984/uint8array-to-string-in-javascript
var strData = new TextDecoder().decode(data);
// Output to console
// console.log(strData);
return strData
}
Insert cell
# Requirements
Insert cell
deck = require.alias({
// optional dependencies
h3: {}
})('deck.gl@latest/dist.min.js')
Insert cell
Insert cell
import {select} from '@jashkenas/inputs'
Insert cell
viewof transcript_radius = slider({
value: 0.5,
min: 0.1,
max: 2.0,
precision: 2,
description: "transcript size"
})
Insert cell
viewof transcript_opacity = slider({
value: 0.75,
min: 0.0,
max: 1.0,
precision: 2,
description: "transcript opacity"
})
Insert cell
d3 = require("d3@5")
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
deck
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more