Published
Edited
Dec 9, 2021
Insert cell
Insert cell
Insert cell
gene_options = ['dog', 'cat', 'bird']
Insert cell
gene_options_dropdown = ['none'].concat(gene_options)
Insert cell
ini_row = 'dog'
Insert cell
ini_col = 'cat'
Insert cell
viewof select_row = select({'options':gene_options_dropdown, value: ini_row})
Insert cell
viewof select_col = select({'options':gene_options_dropdown, value: ini_col})
Insert cell
mutable select_gene = 'none'
Insert cell
Insert cell
gene_colors = ({
'Sstr4': 'orange',
})
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
mutable gene_data = ({})
Insert cell
trx_row_ini = ({
'gene_name': 'dog',
'color': '#ff7f00',
'positions': [[253.34, 17.43],
[377.05, 18.76],
[372.5, 18.94],
[269.97, 21.99],
[242.77, 27.25],
[329.68, 29.79],
[322.93, 29.89],
[347.6, 30.16],
[346.84, 30.76],
[401.38, 31.9]]
})
Insert cell
trx_col_ini = ({
'gene_name': 'cat',
'color': '#ff7f00',
'positions': [[253.34, 17.43],
[397.05, 18.76],
[392.5, 18.94],
[299.97, 21.99],
[292.77, 27.25],
[399.68, 29.79],
[392.93, 29.89],
[397.6, 30.16],
[396.84, 30.76],
[491.38, 31.9]]
})
Insert cell
trx_row = {
var ini_color = 'blue' // trx_row_ini.color
var rgb = d3.color(ini_color)
var inst_color = [rgb.r, rgb.g, rgb.b] // 255

var trx_row = trx_row_ini.positions.map( x => {
return {
'name': trx_row_ini['gene_name'],
'color': inst_color,
'position': x
}
})

return trx_row
}
Insert cell
trx_col = {
var ini_color = 'red' // trx_col_ini.color
var rgb = d3.color(ini_color)
var inst_color = [rgb.r, rgb.g, rgb.b] // 255

var trx_col = trx_col_ini.positions.map( x => {
return {
'name': trx_col_ini['gene_name'],
'color': inst_color,
'position': x
}
})

return trx_col
}
Insert cell
trx_data = [].concat(trx_row, trx_col)
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
transcript_layer = new deck.ScatterplotLayer({
id: 'transcript_layer',
// data: transcript_data,
data: trx_data,
pickable: is_pickable,
// getPosition: d => [d.x, d.y],
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('#select_row').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
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}) => 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
debounce_time = 250
Insert cell
debounced_something = debounce(something, debounce_time);
Insert cell
function debounce(func, wait, immediate) {
// 'private' variable for instance
// The returned function will be able to reference this due to closure.
// Each call to the returned function will share this common timer.
var timeout;

// Calling debounce returns a new anonymous function
return function() {
// reference the context and args for the setTimeout function
var context = this,
args = arguments;

// Should the function be called now? If immediate is true
// and not already in a timeout then the answer is: Yes
var callNow = immediate && !timeout;

// This is the basic debounce behaviour where you can call this
// function several times, but it will only execute once
// [before or after imposing a delay].
// Each time the returned function is called, the timer starts over.
clearTimeout(timeout);

// Set the new timeout
timeout = setTimeout(function() {

// Inside the timeout function, clear the timeout variable
// which will let the next execution run when in 'immediate' mode
timeout = null;

// Check if the function already ran with the immediate flag
if (!immediate) {
// Call the original function with apply
// apply lets you define the 'this' object as well as the arguments
// (both captured before setTimeout)
func.apply(context, args);
}
}, wait);

// Immediate mode and no wait timer? Execute the function..
if (callNow) func.apply(context, args);
}
}

Insert cell
// mutable view_bounds = [mean_x - width/(2*zoom),
// mean_x + width/(2*zoom),
// mean_y - height/(2*zoom),
// mean_y + height/(2*zoom)]

mutable view_bounds = null
Insert cell
mutable inst_zoom = zoom
Insert cell
Math.pow(2,10)
Insert cell
function something(viewState){
var height = viewState.height
var width = viewState.width

// log2 zoom for python
mutable inst_zoom = viewState.zoom
var zoom = Math.pow(2, viewState.zoom)

var target_x = viewState.target[0]
var target_y = viewState.target[1]
var min_x = target_x - width/(2*zoom)
var max_x = target_x + width/(2*zoom)

var min_y = target_y - height/(2*zoom)
var max_y = target_y + height/(2*zoom)

mutable view_bounds = [min_x, max_x, min_y, max_y]

mutable visible_transcripts = true
// if (zoom > detail_zoom_thresh){

// } else {
// mutable view_bounds = null
// // mutable visible_transcripts = false
// // mutable fovs = []
// }
}
Insert cell
// deckgl.getBounds()
Insert cell
deckgl = ini_deckgl(container)
Insert cell
// d3.max(transcript_data,
// mean_x = d3.mean(transcript_data.map(x => x['x']))
mean_x = d3.mean(trx_data.map(x => x['position'][0]))
Insert cell
// mean_y = d3.mean(transcript_data.map(x => x['y']))
mean_y = d3.mean(trx_data.map(x => x['position'][1]))
Insert cell
min_zoom = -5
Insert cell
zoom = 2
Insert cell
max_zoom = 10
Insert cell
initial_view_state = ({
target: [mean_x, mean_y, 0],
zoom: zoom,
minZoom: min_zoom,
maxZoom: max_zoom
})
Insert cell
Insert cell
// inst_lat = 1
Insert cell
// inst_lng = 1
Insert cell
height = 800
Insert cell
Insert cell
detail_zoom_thresh = 2
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.75,
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