Public
Edited
Sep 12, 2023
Insert cell
Insert cell
dashboard = html`

<div style="display: flex;">

<div style="margin-left: 15px; margin-right: 0px; border:1px; text-align:right;">${viewof view_type} </div>

<div style="margin-left: 5px; margin-right: 0px; border:1px; text-align:right;">${viewof show_image} </div>

<div style="margin-left: 0px; margin-right: 0px; border:1px; text-align:right;">${viewof show_trx} </div>

<div id="meta_dropdown", style="margin-left: 25px; border:1px; text-align:left;">${viewof select_gene_dropdown} </div>

<div style="margin-left: 20px; margin-right: 5px; border:1px; text_align:center;">${viewof polygon_opacity}</div>


<div style="margin-left: 20px; margin-right: 5px; border:1px; text_align:center;">${viewof trx_radius}</div>

<div style="margin-left: 0px; margin-right: 1px; border:1px; text_align:left;"></div>
</div>

<div>
${container}
</div>

`
// <div style="margin-left: 5px; margin-right: 1px; border:1px; text_align:left;">${viewof transcripts_paritioned}</div>

// <div style="margin-left: 2px; margin-right: -100px; border:1px; text_align:left;">${viewof show_image}</div>


Insert cell
viz_width = 800
Insert cell

container = {

return html `<div id='the-container' style="height:${height}px; width:${viz_width}; border-style:solid; border-color:#d3d3d3; border-width:1px; position: relative;"></div>`
}

// container = html `<div style="height:800px; border-style:solid; border-color:#d3d3d3; border-width:1px"></div>`
Insert cell
height = 800
Insert cell
viewof view_type = {
const element = html`
<div style="display: inline-block; user-select: none;"></div>`;

d3.select(element)
.selectAll('div')
.data(['2D', '3D'])
.join('span')
// .style('min-width', '200px')
.style('min-width', '200px')
.style('max-width', '200px')
.style('margin-right', '5px')
.text(d => d)
.style('font-weight', '550px')
.style("font-family", "sans-serif")
.style("font-size", "16")
.style("text-anchor", "end")
.style('font-weight', 'bold')
.style('color', d => d === ini_view_type ? 'blue': '#808080')
.on('click', function(d){
d3.select(element).selectAll('span')
.style('color', '#808080')
d3.select(this)
.style('color', 'blue')
element.value = d.replace(', ', '')
element.dispatchEvent(new CustomEvent("input"));
})

element.value = ini_view_type
element.dispatchEvent(new CustomEvent("input"))

return element
}
Insert cell
ini_image_type = true
Insert cell
// toggle image on and off
viewof show_image = {
const element = html`
<div style="display: inline-blockd; user-select: none;"></div>`;

d3.select(element)
.selectAll('div')
.data(['IMG'])
.join('span')
.style('min-width', '200px')
.style('max-width', '200px')
.style('margin-right', '10px')
.text(d => d)
.style('font-weight', '550px')
.style("font-family", "sans-serif")
.style("font-size", "16")
.style("text-anchor", "end")
.style('font-weight', 'bold')
.style('color', d => {
var inst_color
if (ini_image_type === true){
inst_color = 'blue'
} else {
inst_color = '#808080'
}
return inst_color
})
.on('click', function(d){
var current_color = d3.select(this).style('color')

if (current_color !== 'blue'){
d3.select(this)
.style('color', 'blue')
element.value = true
} else {
d3.select(this)
.style('color', '#808080')
element.value = false
}
element.dispatchEvent(new CustomEvent("input"));
})

element.value = ini_image_type
element.dispatchEvent(new CustomEvent("input"))

return element
}
Insert cell
show_trx
Insert cell
ini_trx_type = true
Insert cell
// toggle image on and off
viewof show_trx = {
const element = html`
<div style="display: inline-blockd; user-select: none;"></div>`;

d3.select(element)
.selectAll('div')
.data(['TRX'])
.join('span')
.style('min-width', '200px')
.style('max-width', '200px')
.style('margin-right', '10px')
.text(d => d)
.style('font-weight', '550px')
.style("font-family", "sans-serif")
.style("font-size", "16")
.style("text-anchor", "end")
.style('font-weight', 'bold')
.style('color', d => {
var inst_color
if (ini_trx_type === true){
inst_color = 'blue'
} else {
inst_color = '#808080'
}
return inst_color
})
.on('click', function(d){
var current_color = d3.select(this).style('color')

if (current_color !== 'blue'){
d3.select(this)
.style('color', 'blue')
element.value = true
} else {
d3.select(this)
.style('color', '#808080')
element.value = false
}
element.dispatchEvent(new CustomEvent("input"));

})

element.value = ini_trx_type
element.dispatchEvent(new CustomEvent("input"))

return element
}
Insert cell
Object.keys(cat_colors).sort()
Insert cell
viewof select_gene_dropdown = select({'options':['none'].concat(Object.keys(cat_colors).sort()), value: 'none'})
Insert cell
mutable select_gene = select_gene_dropdown
Insert cell
scale_z = 15
Insert cell
cat_colors = ({
'dog': 'blue',
'elephant': 'purple',
'tiger': 'orange'
})
Insert cell
cell_colors = ({
'neuron': 'blue',
'immune': 'purple',
'other': 'orange'
})
Insert cell
// height = 800
Insert cell
// polygon_data = [
// {
// 'name': 'something',
// 'coordinates': [[0,1], [1,1], [2,2]],
// 'z': 10,
// 'cell_type' : 'neuron',
// 'z_level': 1
// },
// {
// 'name': 'something2',
// 'coordinates': [[4,4], [10,4], [10,10],[4,10]],
// 'z': 10,
// 'cell_type': 'immune',
// 'z_level': 2
// }
// ]
Insert cell
// polygon_data3d = [
// {
// 'name': 'something',
// 'coordinates': [[0,1,30], [1,1,30], [2,2,30]],
// 'cell_type': 'neuron',
// 'z': 3
// },
// {
// 'name': 'something2',
// 'coordinates': [[4,4,15], [10,4,15], [10,10,15],[4,10,15]],
// 'cell_type': 'immune',
// 'z': 3
// }
// ]
Insert cell
// scatter_data = [{'name': 'dog', 'x': 0, 'y': 1, 'z': 1, 'partition': 0},
// {'name': 'elephant', 'x': 2, 'y': 2, 'z': 2, 'partition': 1},
// {'name': 'tiger', 'x': 4, 'y': 5, 'z': 3, 'partition': 1}]
Insert cell
// blue square image
image = '"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAHUlEQVR4nGNkYPjPQC5gIlvnqOZRzaOaRzVTRTMAIJ4BJ6WiocQAAAAASUVORK5CYII="'
Insert cell
image_proc = image.slice(1,-1)
Insert cell
cell_border_width = 3
Insert cell
ini_cell_opacity = .5
Insert cell
import {slider, select} from '@jashkenas/inputs'
Insert cell
viewof polygon_opacity = slider({
value: ini_cell_opacity,
min : 0,
max : 1,
step : .1,
description: "Cell Opacity",
})
Insert cell
ini_trx_radius = 1
Insert cell
viewof trx_radius = slider({
value: ini_trx_radius,
min : 0.1,
max : 10,
step : .1,
description: "Transcript Radius",
})
Insert cell
viewof transcripts_paritioned = Inputs.toggle({
label : "Partitioned Transcripts Only",
// value : false,
values :[1,0]
})
Insert cell
// viewof zlayer = Inputs.select(
// new Map([['All',[0,1,2,3,4,5,6]],["0",[0]],["1",[1]],["2",[2]],["3",[3]],["4",[4]],["5",[5]],["6",[6]],['None',[]]]),
// {
// value : [0,1,2,3,4,5,6],
// label : 'Transcripts Z-level'}
// )
Insert cell
// this way we can perform a filtering of the scattered data using the selected gene
scatter_data_proc = scatter_data
// .filter(item => zlayer.includes(item.z))
.filter(d => {
if (select_gene === 'none'){
return d
} else {
return d.name === select_gene
}
})
Insert cell
select_gene
Insert cell
filtered_scatter_data = scatter_data.filter(item => item.partition !== -1)
.filter(d => {
if (select_gene === 'none'){
return d
} else {
return d.name === select_gene
}
})
// .filter(d => {
// if (select_gene !== 'none'){
// return d
// }
// })
Insert cell
bitmap_layer = new deck.BitmapLayer({
id: 'bitmap_layer',
bounds:image_bounds,
image:image_proc,
visible: show_image,
updateTriggers: {
data: view_type,
},
});
Insert cell
pointcloud_layer = new deck.PointCloudLayer({
id: 'pointcloud_layer',
data: scatter_data_proc,
getPosition: d => {
return [d.x, d.y, scale_z * d.z + 1/2*scale_z]
},
getColor: d => {
var inst_color
var unselected_color = [0, 0, 0, 1]

var rgb = d3.color(cat_colors[d.name])
if (select_gene === 'none'){
inst_color = [rgb.r, rgb.g, rgb.b, 255]
} else {
inst_color = unselected_color
if (d.name === select_gene){
inst_color = [rgb.r, rgb.g, rgb.b, 255]
}
}
return inst_color
},
getRadius: trx_radius,
pickable: true,
pointSize:trx_radius,
sizeUnits:'meters',
// autoHighlight: true,
highlightColor: d => [50, 50, 50],
radiusMinPixels: radius_min_pixels,
updateTriggers: {
data: view_type,
getColor: [select_gene]
},
visible: show_trx,
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
scatter_layer = new deck.ScatterplotLayer({
id: 'scatter_layer',
data: scatter_data_proc,
getPosition: d => {
return [d.x, d.y]
},
getFillColor: d => {
var inst_color
var rgb = d3.color(cat_colors[d.name])
inst_color = [rgb.r, rgb.g, rgb.b, 255]
return inst_color
},
getRadius: trx_radius,
pickable: true,
highlightColor: d => [50, 50, 50],
radiusMinPixels: radius_min_pixels,
updateTriggers: {
data: view_type,
},
visible: show_trx,
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
opacity_255 = d3.scaleLinear().domain([0, 1]).range([0, 255])
Insert cell
polygon_layer_3d = new deck.PolygonLayer({
id: 'polygon_layer_3d',
data: polygon_data3d,
getFillColor: d => {
var inst_color
var rgb = d3.color(cell_colors[d.cell_type])
inst_color = [rgb.r, rgb.g, rgb.b, opacity_255(polygon_opacity)]
return inst_color
},
getLineColor: d => {
var inst_color
var rgb = d3.color(cell_colors[d.cell_type])
inst_color = [rgb.r, rgb.g, rgb.b, opacity_255(polygon_opacity)]
return inst_color
},
getLineWidth: d => 100,
getPolygon: d => d.coordinates,
getElevation: d => scale_z,

lineWidthMinPixels: 30,
stroked: true,
filled: false, // nick-working

// // try toggling extruded for reusing with2D
extruded : true,

wireframe: true,
pickable: true,
visible: polygon_opacity !== 0,
updateTriggers: {
getFillColor: polygon_opacity,
getLineColor: polygon_opacity,
visible: polygon_opacity,
data: view_type,
},
});
Insert cell
polygon_data = [
{
'name': 'something',
'coordinates': [
[0,1], [1,1], [2,2],
[0,0.5], [0.5,0.5], [1.0,1.0]
],
'z': 0
},
{
'name': 'something',
'coordinates': [[10,11], [10,10], [12,12]],
'z': 1
}
]
Insert cell
polygon_layer_2d = new deck.PolygonLayer({
id: 'polygon_layer',
data: polygon_data_2d,
getFillColor: d => {
var inst_color
var rgb = d3.color(cell_colors[d.cell_type])
inst_color = [rgb.r, rgb.g, rgb.b, opacity_255(polygon_opacity)]
return inst_color
},
getLineColor: d => {
var inst_color
var rgb = d3.color(cell_colors[d.cell_type])
inst_color = [rgb.r, rgb.g, rgb.b, opacity_255(polygon_opacity)]
return inst_color
},
getLineWidth: d => cell_border_width,
getPolygon: d => d.coordinates,
stroked: true,
filled: false,
visible: polygon_opacity !== 0,
pickable: true,
updateTriggers: {
data: view_type,
getFillColor: polygon_opacity,
getLineColor: polygon_opacity,
visible: polygon_opacity,
},
});
Insert cell
layers = {
var layers
if (view_type === '3D'){
layers = [bitmap_layer, polygon_layer_3d, pointcloud_layer]
} else {
layers = [bitmap_layer, polygon_layer_2d, scatter_layer]
}
return layers
}
Insert cell
deckgl.setProps({layers: layers});
Insert cell
// deck = require.alias({
// // optional dependencies
// h3: {},
// s2Geometry: {}
// })('deck.gl@8.3.7/dist.min.js')

deck = require.alias({
// optional dependencies
h3: {}
})('deck.gl@8.8.11/dist.min.js')
Insert cell
// image_bounds = [[0, -image_size], [0, 0], [image_size, 0], [image_size, -image_size]]

// [[left, bottom], [left, top], [right, top], [right, bottom]]
image_bounds = [[0, -image_size], [0, 0], [image_size, 0], [image_size, -image_size]]
Insert cell
image_size = 10
Insert cell
// radius = 0.25
Insert cell
radius_min_pixels = 0.5
Insert cell
center_x = 0
Insert cell
center_y = 0
Insert cell
ini_view_type = '3D'
Insert cell
flipY = false
Insert cell
// function to redefined view
view = {
var view
if (view_type == '3D'){
view = new deck.OrbitView({id: 'orbit'})
} else {
view = new deck.OrthographicView({id: 'ortho', flipY: flipY})
}
return view
}
Insert cell
deckgl = {
container.innerHTML = '';
// var INITIAL_VIEW_STATE = INITIAL_VIEW_STATE_3D
return new deck.DeckGL({
container,
views:[view],
initialViewState:INITIAL_VIEW_STATE_3D,
controller: true,
getTooltip: ({object, layer}) => {
if (object){
if (layer.id === 'polygon_layer_3d'){
return object && ` ${object.name}\n${object.cell_type} `
} else{
return object && `${object.name}`
}
} },
});
}
Insert cell
INITIAL_VIEW_STATE_2D = ({
target: [center_x, center_y, 0],
zoom: zoom,
minZoom:min_zoom,
})
Insert cell
INITIAL_VIEW_STATE_3D = ({
target: [center_x, center_y, 0],
rotationX: 90,

// rotationX: 180,
// rotationOrbit: 180,
// rotationOrbit: 270,
rotationOrbit: 0,

// minRotationX: -720,
// minRotationOrbit: -720,
zoom: zoom,
minZoom:min_zoom
})
Insert cell
// function to define ini_view_state, re-calc on view_type update
INITIAL_VIEW_STATE = {
var INITIAL_VIEW_STATE
if (view_type == '3D'){
INITIAL_VIEW_STATE = INITIAL_VIEW_STATE_3D
} else {
INITIAL_VIEW_STATE = INITIAL_VIEW_STATE_2D
}
return INITIAL_VIEW_STATE
}
Insert cell
// INITIAL_VIEW_STATE_3D = ({
// target: [center_x, center_y, 0],
// rotationX: 90,
// // rotationOrbit: -720,
// // minRotationX: -720,
// // minRotationOrbit: -720,
// zoom: zoom,
// minZoom:min_zoom
// })
Insert cell
min_zoom = -1.5
Insert cell
zoom = 0
Insert cell
d3 = require("d3@5")
Insert cell
Insert cell
pako = require('pako/dist/pako.min.js')
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
return strData
}
Insert cell
// geojson_string = decode_zipped_string(zip_geojson_string)
Insert cell
zip_polygon_data3d = 'eJxtjcEKwjAMhl8l5JxD282Lr1KKDBe0sKaydQcV331dDirbIIH/I+T//BulS4xnwCknLvcoNyTAa85jH6UrPNWb94bAEjQmEHj7lx2B0xzWJx6GS3k+tE54HrOsXa+KzYfgQOWOXC1BHXtSl9mArlL7hZ07pjQL/9xhAXupP1k='
Insert cell
// zip_polygon_data3d = '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'
Insert cell
polygon_data3d = JSON.parse(decode_zipped_string(zip_polygon_data3d))
Insert cell
zip_scatter_data = 'eJyLrlbKS8xNVbJSUErJT1fSUVCqALINgHQlkDYE0lVQuiCxqCSzJDM/DyRfq6OA0Jiak1qQkZhXAtNtBNVtBNVthKbbEEV3SWZ6ahFMqwlUqylUqzGG1lgAgEsvhQ=='
Insert cell
scatter_data = JSON.parse(decode_zipped_string(zip_scatter_data))
Insert cell
polygon_data3d
Insert cell
polygon_data_2d = polygon_data3d.map (d => ({
...d,
coordinates: d.coordinates.map(coord => coord.slice(0,2))
}))
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