Public
Edited
Aug 15, 2023
Insert cell
Insert cell
height = 800
Insert cell
Insert cell

container = {

return html `<div id='the-container' style="height:${height}px; 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
dashboard = html`

<div style="display: flex;">

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

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

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

<div>
${container}
</div>

`
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
poly_line_width = 3
Insert cell
ini_opacity = .5
Insert cell
import {slider, select} from '@jashkenas/inputs'
Insert cell
viewof polygon_opacity = slider({
value: ini_opacity,
min : 0,
max : 1,
step : .1,
description: "Polygon Opacity"
})
Insert cell
viewof transcripts_paritioned = Inputs.toggle({
label : "Partitioned Transcripts Only",
// value : false,
values :[1,0]
})
Insert cell
viewof show_image = Inputs.toggle({label: "Image", value: true})
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: transcripts_paritioned === 0? scatter_data_proc: filtered_scatter_data.filter(item => zlayer.includes(item.z)),
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: radius,
pickable: true,
pointSize:2,
sizeUnits:'meters',
// autoHighlight: true,
highlightColor: d => [50, 50, 50],
radiusMinPixels: radius_min_pixels,
updateTriggers: {
data: view_type,
getColor: [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
// scatter_layer = new deck.ScatterplotLayer({
// id: 'scatter_layer',
// data: transcripts_paritioned === 0? scatter_data.filter(item => zlayer.includes(item.z)): filtered_scatter_data.filter(item => zlayer.includes(item.z)),
// 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: radius,
// pickable: true,
// // autoHighlight: true,
// highlightColor: d => [50, 50, 50],
// radiusMinPixels: radius_min_pixels,
// updateTriggers: {
// data: view_type,
// // getFillColor: select_meta,
// // getPosition: map_type
// },
// })
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,

// // try toggling elevation off for reusing the layer in 2D
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 = new deck.PolygonLayer({
id: 'polygon_layer',
data: polygon_data_2d,
getFillColor: [250, 0, 0, 0],
getLineColor: [250, 0, 0],
getLineWidth: d => poly_line_width,
getPolygon: d => d.coordinates,
stroked: true,
filled: true,
// wireframe: true,
pickable: true,
// opacity: rescue_opacity
updateTriggers: {
data: view_type,
},
});
Insert cell
// polygon_layer = new deck.PolygonLayer({
// id: 'polygon_layer',
// // data: polygon_data,
// data: polygon_data.filter(item => zlayer.includes(item.z_level)),
// getFillColor: d => {
// var inst_color
// var rgb = d3.color(cell_colors[d.cell_type])
// inst_color = [rgb.r, rgb.g, rgb.b, 255]
// 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, 255]
// return inst_color
// },
// getLineWidth: d => poly_line_width,
// getPolygon: d => d.coordinates,
// stroked: true,
// filled: true,
// wireframe: false,
// pickable: true,
// // opacity: 0.1, // 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]
}
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')
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
// function to redefined view
view = {
var view
if (view_type == '3D'){
view = new deck.OrbitView({id: 'orbit'})
} else {
view = new deck.OrthographicView({id: 'ortho'})
}
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,
// rotationOrbit: -720,
// 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