Public
Edited
Sep 18, 2023
1 fork
Importers
Insert cell
Insert cell
zoom_data
Insert cell
cgm_container = html `<div style="height:${viz_height}px; width:${viz_width}"></div>`
Insert cell
col_label_height = 20
Insert cell
col_label_data = {

let matrix_index = 0;

var index_col = 0

var num_points = num_rows * 1
return new Array(num_points).fill(0).map( _ => {

var index_col = matrix_index % num_cols

if (matrix_index % 1 === 0){
index_col += 1;
}
const p = {
position: [col_offset * index_col - col_offset/2, col_label_height],
name: 'col-' + index_col
};
matrix_index += 1;
return p;
});
}
Insert cell
col_label_layer = new deck.TextLayer({
id: 'col-label-layer',
data: col_label_data, // This should be the same data source you used for your other layers
getPosition: d => d.position,
getText: d => d.name,
getSize: inst_font_size,
getColor: [0, 0, 0], // Text color as an RGBA array
getAngle: 45, // Optional: Text angle in degrees
getTextAnchor: 'start', // middle
getAlignmentBaseline: 'bottom',
fontFamily: 'Arial',
sizeUnits: 'pixels',
updateTriggers: {
getSize: inst_font_size
},
pickable: true,
// onHover: (info, event) => console.log('Hovered:', info), // , event
})
Insert cell
// zoom of 1, min pan 300 ( 0, 300/1)
// zoom of 2, min pan 150 (-150, 300/2)
// zoom of 3, min pan 100 (-200, 300/3)
// zoom of 4, min of 75 (-225, 300/4)

// max
// zoom of 1, max of 300 (0
// zoom of 2, max of 450 (+150
// zoom of 3, max of 500 (+200
// zoom of 4 max of 525 (+225
// zoom of 5 max of 540s
// zoom of 6 max of 550

// y pan restrictions
// 1 -> 360 (300/1 + 60)
// 2 -> 210 (300/2 + 60)
// 3 -> 160 (100/3 + 60)
Insert cell
// X: pan to left (higher), pan to right (lower)
Insert cell
zoom_data
Insert cell
num_rows = 10
Insert cell
num_cols = 10
Insert cell
base_font_size = 100
Insert cell
ini_font_size = base_font_size / num_rows
Insert cell
mutable inst_font_size = ini_font_size
Insert cell
mat_height = 600
Insert cell
mat_width = 600
Insert cell
row_region_width = 90
Insert cell
col_region_height = col_cat_height * num_cats_col + col_label_height + 20
Insert cell
row_height = (mat_height/num_rows) * 0.999
Insert cell
col_width = (mat_width/num_cols) * 0.999
Insert cell
row_offset = mat_height/num_rows
Insert cell
col_offset = mat_width/num_cols
Insert cell
row_cat_width = 9
Insert cell
col_cat_height = 9
Insert cell
// width of row category bars
row_cat_offset = 10
Insert cell
// height of column category bars
col_cat_offset = 10
Insert cell
// position the cats
label_row_x = 15
Insert cell
// position the cats
label_col_y = 25
Insert cell
viz_width = mat_width + row_region_width
Insert cell
viz_height = mat_height + col_region_height
Insert cell
label_buffer = 1
Insert cell
deck = require.alias({
// optional dependencies
h3: {}
})('deck.gl@latest/dist.min.js')
Insert cell
Insert cell
views = [
new deck.OrthographicView({
id: 'matrix',
x: ( row_region_width + label_buffer)+ 'px',
y: ( col_region_height + label_buffer) + 'px',
width: mat_width + 'px',
height: mat_height + 'px',
controller: {scrollZoom: true, inertia: false, zoomAxis: 'all'},
}),

new deck.OrthographicView({
id: 'rows',
x: '0px',
y: (col_region_height + label_buffer) + 'px',
width: row_region_width + 'px',
height: mat_height + 'px',
controller: {scrollZoom: true, inertia: false, zoomAxis: 'Y'},
}),

new deck.OrthographicView({
id: 'cols',
x: (row_region_width + label_buffer) + 'px',
y: '0px',
width: mat_width + 'px',
height: col_region_height + 'px',
controller: {scrollZoom: true, inertia: false, zoomAxis: 'X'},
}),
]
Insert cell
Insert cell
ini_pan_x = mat_width/2
Insert cell
// not sure why I need to add row_offset?
// ini_y = mat_height/2 + row_offset
ini_pan_y = mat_height/2 + row_offset
Insert cell
ini_zoom_x = 0
// ini_zoom_x = -1
Insert cell
ini_zoom_y = 0
// ini_zoom_y = -1
Insert cell
Insert cell
// update zoom_data inplace
// this takes as an input the mutable zoom_data
update_zoom_data = (zoom_data, viewId, zoom, target) => {
if (viewId === 'matrix') {

// update pans
zoom_data.pan_x = target[0];
zoom_data.pan_y = target[1];

// update zooms
zoom_data.zoom_x = zoom[0]
zoom_data.zoom_y = zoom[1]
} else if (viewId === 'cols') {

// update pan_x
zoom_data.pan_x = target[0]
// update zooms
zoom_data.zoom_x = zoom[0]

// // switch to y zoom
// ////////////////////////
// // update pan_x
// zoom_data.pan_x = target[0]
// // update zooms
// zoom_data.zoom_y = zoom[1]
} else if (viewId === 'rows') {

// update pan_y
zoom_data.pan_y = target[1];
// update zooms
zoom_data.zoom_y = zoom[1]
}
}
Insert cell
mat_width
Insert cell
ini_pan_x
Insert cell
ini_global_view_state = () => {
let globalViewState = {
matrix: {
// target: target,
target: [ini_pan_x, ini_pan_y],
zoom: [ini_zoom_x, ini_zoom_y],
},
rows: {
target: [label_row_x, ini_pan_y],
zoom: [ini_zoom_x, ini_zoom_y],
},
cols: {
target: [ini_pan_x, label_col_y],
zoom: [ini_zoom_x, ini_zoom_y],
},
}
return globalViewState
}
Insert cell
layerFilter = ({layer, viewport}) => {

// console.log(viewport.id, layer.id)
if (viewport.id === 'matrix' && layer.id === 'matrix-layer'){
return true
} else if (viewport.id === 'rows' && layer.id === 'row-layer'){
return true
} else if (viewport.id === 'cols' && layer.id === 'col-layer'){
return true
} else if (viewport.id === 'rows' && layer.id === 'row-label-layer'){
return true
} else if (viewport.id === 'cols' && layer.id === 'col-label-layer'){
return true
}
return false
}
Insert cell
getTooltip = ({object, layer}) => {
if (object) {
// Check which layer the tooltip is currently over
if (layer.id === 'row-label-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Row Label: ${object.name}`,
style: {color: "white"},
};
}
else if (layer.id === 'col-label-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Col Label: ${object.name}`,
style: {color: "white"},
};
}
else if (layer.id === 'row-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Row Label: ${object.name}`,
style: {color: "white"},
};
}
else if (layer.id === 'col-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Col Label: ${object.name}`,
style: {color: "white"},
};
}
else if (layer.id === 'matrix-layer') {
// Display the default tooltip for other layers
return {
html: `Row: ${object.row} <br> Column: ${object.col}`,
style: {color: "white"},
};
}
}
}
Insert cell
// trying to define a mutable zoom_data outside of the deckgl cell
mutable zoom_data = ({
pan_x: ini_pan_x,
pan_y: ini_pan_y,
zoom_x: ini_zoom_x,
zoom_y: ini_zoom_y,
})
Insert cell
// mutable globalViewState = ini_global_view_state()
Insert cell
ini_view_state = ini_global_view_state()
Insert cell
curate_pan_y = (target_y, zoom_curated_y, ini_pan_y) => {

// ini_pan_y = ini_pan_y// - row_offset

var pan_curated_y

var zoom_factor_y = Math.pow(2, zoom_curated_y)

// var min_pan_y = ini_pan_y/zoom_factor_y
var min_pan_y = (ini_pan_y - row_offset)/zoom_factor_y + row_offset

// calculating the shift to the min, to re-use for the max
var min_diff = ini_pan_y - min_pan_y
var max_pan_y = ini_pan_y + min_diff

if (target_y <= min_pan_y){
// console.log('below min')
pan_curated_y = min_pan_y
} else if (target_y > max_pan_y) {
pan_curated_y = max_pan_y
// console.log('above min')
} else {
pan_curated_y = target_y
// console.log('within bounds')
}

// console.log(zoom_factor_y.toFixed(2),
// target_y.toFixed(2),
// min_pan_y.toFixed(2),
// max_pan_y.toFixed(2),
// pan_curated_y.toFixed(2),
// zoom_data['pan_y'].toFixed(2))
// // (zoom_data['pan_x'] - mat_width/2).toFixed(2))
return pan_curated_y// + row_offset
}
Insert cell
curate_pan_x = (target_x, zoom_curated_x, ini_pan_x) => {

var pan_curated_x

var zoom_factor_x = Math.pow(2, zoom_curated_x)

var min_pan_x = ini_pan_x/zoom_factor_x

// calculating the shift to the min, to re-use for the max
var min_diff = ini_pan_x - min_pan_x
var max_pan_x = ini_pan_x + min_diff

if (target_x <= min_pan_x){
// console.log('below min')
pan_curated_x = min_pan_x
} else if (target_x > max_pan_x) {
pan_curated_x = max_pan_x
// console.log('above min')
} else {
pan_curated_x = target_x
// console.log('within bounds')
}

// console.log(zoom_factor_x.toFixed(2),
// target_x.toFixed(2),
// min_pan_x.toFixed(2),
// max_pan_x.toFixed(2),
// pan_curated_x.toFixed(2),
// zoom_data['pan_x'].toFixed(2))
// // (zoom_data['pan_x'] - mat_width/2).toFixed(2))
return pan_curated_x
}
Insert cell
// new version with fewer arguments
// this does not need the mutable zoom_data since it
// is not going to be modifying zoom_data
redefine_global_view_state = (zoom_data, viewId, zoom, target) => {
var globalViewState

var min_zoom_x = 0
var min_zoom_y = 0
var zoom_curated_x = Math.max(min_zoom_x, zoom[0])
var zoom_curated_y = Math.max(min_zoom_x, zoom[1])

var pan_curated_x = curate_pan_x(target[0], zoom_curated_x, ini_pan_x)
// var pan_curated_y = ini_pan_y // target[1]
var pan_curated_y = curate_pan_y(target[1], zoom_curated_y, ini_pan_y)

if (viewId === 'matrix') {
globalViewState = {
matrix: {
// zoom: [zoom[0], zoom[1]],
zoom: [zoom_curated_x, zoom_curated_y],
// target: [target[0], target[1]]
target: [pan_curated_x, pan_curated_y]
},
rows: {
// zoom: [ini_zoom_x, zoom[1]],
zoom: [ini_zoom_x, zoom_curated_y],
// target: [label_row_x, target[1]]
target: [label_row_x, pan_curated_y]
},
cols: {
// zoom: [zoom[0], ini_zoom_y],
zoom: [zoom_curated_x, ini_zoom_y],
// target: [target[0], label_col_y]
target: [pan_curated_x, label_col_y]
},
}
} else if (viewId === 'cols'){
globalViewState = {
matrix: {
// zoom: [zoom[0], zoom_data.zoom_y],
zoom: [zoom_curated_x, zoom_data.zoom_y],
// target: [target[0], zoom_data.pan_y]
target: [pan_curated_x, zoom_data.pan_y]
},
rows: {
// zoom: [ini_zoom_x, zoom_data.zoom_y],
zoom: [ini_zoom_x, zoom_data.zoom_y],
// target: [label_row_x, zoom_data.pan_y]
target: [label_row_x, zoom_data.pan_y]
},
cols: {
// zoom: [zoom[0], ini_zoom_y],
zoom: [zoom_curated_x, ini_zoom_y],
// target: [target[0], label_col_y]
target: [pan_curated_x, label_col_y]
},
}

} else if (viewId === 'rows'){
globalViewState = {
matrix: {
// zoom: [zoom_data.zoom_x, zoom[1]],
zoom: [zoom_data.zoom_x, zoom_curated_y],
// target: [zoom_data.pan_x, target[1]]
target: [zoom_data.pan_x, pan_curated_y]
},
rows: {
// zoom: [ini_zoom_x, zoom[1]],
zoom: [ini_zoom_x, zoom_curated_y],
// target: [label_row_x, target[1]]
target: [label_row_x, pan_curated_y]
},
cols: {
// zoom: [zoom_data.zoom_x, ini_zoom_y],
zoom: [zoom_data.zoom_x, ini_zoom_y],
// target: [zoom_data.pan_x, label_col_y]
target: [zoom_data.pan_x, label_col_y]
},
}
}

return globalViewState
}
Insert cell
on_view_state_change = ({viewState, viewId}) => {
const {zoom, target, offset} = viewState;

// // checking target!!!
// console.log('target', target)

// this takes the latest non-mutable zoom_data since it does
// not update zoom_data
var global_view_state = redefine_global_view_state(zoom_data, viewId, zoom, target)

var zoom_factor_x = Math.pow(2, zoom_data.zoom_x)
mutable inst_font_size = ini_font_size * zoom_factor_x

// this takes mutable zoom_data since it updates zoom_data's state
update_zoom_data(mutable zoom_data, viewId, zoom, target)

var updated_view_state = {...global_view_state}

// this will only update the zoom state for the current layer
// return updated_view_state
// use setProps to update viewState with updated_view_state
deckgl.setProps({viewState: updated_view_state});
}
Insert cell
deckgl.setProps({onViewStateChange: on_view_state_change})
Insert cell
deckgl = new deck.DeckGL({
// this needs to be provided at initialization
container: cgm_container,
})
Insert cell
deckgl.setProps({initialViewState: ini_view_state})
Insert cell
deckgl.setProps({views})
Insert cell
deckgl.setProps({getTooltip})
Insert cell
deckgl.setProps({layerFilter})
Insert cell
deckgl.setProps({layers});
Insert cell
row_label_layer = new deck.TextLayer({
id: 'row-label-layer',
data: row_label_data, // This should be the same data source you used for your other layers
getPosition: d => d.position,
getText: d => d.name, // Replace 'label' with the property in your data that contains the text you want to display
getSize: d => inst_font_size,
getColor: [0, 0, 0], // Text color as an RGBA array
getAngle: 0, // Optional: Text angle in degrees
getTextAnchor: 'end', // middle
getAlignmentBaseline: 'center',
fontFamily: 'Arial',
sizeUnits: 'pixels',
updateTriggers: {
getSize: inst_font_size
},
pickable: true,
// onHover: (info, event) => console.log('Hovered:', info), // , event
})
Insert cell
layers = [mat_layer, row_cat_layer, col_cat_layer, row_label_layer, col_label_layer]
Insert cell
defaultProps = {
return {
// Center of each circle, in [longitude, latitude, (z)]
getPosition: {type: 'accessor', value: x => x.position},
// Color of each circle, in [R, G, B, (A)]
// getColor: {type: 'accessor', value: [0, 0, 0, 255]},
getColor: {type: 'accessor', value: [0, 0, 0, 50]},
}
}
Insert cell
getMatrixModel = {
const {Model, Geometry} = luma;
// model object creation
// import {picking} from '@deck.gl/core';
// deckgl.picking

// required for tooltip
const {picking} = deck

// console.log(picking)
return gl => {

// Four corners of the quad
const positions = new Float32Array([0, 0,
0, row_height,
col_width, row_height,
col_width, 0]);
const geometry = new Geometry({
drawMode: gl.TRIANGLE_FAN,
vertexCount: 4,
attributes: {
positions: {
size: 2,
value: positions
}
}
});
return new Model(gl, {
vs: vertexShader,
fs: fragmentShader,
geometry,
isInstanced: true,
// required for tooltip
modules: [picking]
});
}
}
Insert cell
Insert cell
// working on real data
network = fetch("https://raw.githubusercontent.com/MaayanLab/clustergrammer/master/json/mult_view.json")
.then(response => response.json())
Insert cell
Insert cell
mat_data = {

let matrix_index = 0;

var index_row = 0

var num_points = num_rows * num_cols
return new Array(num_points).fill(0).map( _ => {

var index_col = matrix_index % num_cols

if (matrix_index % num_cols === 0){
index_row += 1;
}
var inst_red = parseInt(255 * (index_row/num_rows))
var inst_blue = parseInt(255 * (index_col/num_cols))

var inst_color
if (index_col >= index_row){
inst_color = [0, 0, 255]
} else {
inst_color = [255, 0, 0]
}

var inst_opacity = parseInt(255 * matrix_index/num_points)
const p = {
position: [col_offset * index_col, row_offset * index_row],
color: [inst_color[0], inst_color[1], inst_color[2], inst_opacity],
value: ((index_row/num_rows) + (index_col/num_cols))/2,
row: index_row,
// seem to need to add index to col
col: index_col + 1,
};
matrix_index += 1;
return p;
});
}
Insert cell
mat_layer = {
const {Layer} = deck;
class MatrixLayer extends Layer {
initializeState() {
const {gl} = this.context;

// Register attributes
this.getAttributeManager().addInstanced({
instancePositions: {
size: 3,
type: gl.DOUBLE,
accessor: 'getPosition'
},
instanceColors: {
size: 4,
normalized: true,
type: gl.UNSIGNED_BYTE,
accessor: 'getColor',
defaultValue: [0, 0, 0, 255]
},
// createing a picking color attribute
customPickingColors: {
size: 3,
type: gl.UNSIGNED_BYTE,
update: this.calculatePickingColors
// update: calculatePickingColors
}
});
// Save the model in layer state
this.setState({
model: getMatrixModel(gl)
});
}
updateState() {
// Retrieve the model from layer state
this.state.model.setUniforms({
// smoothRadius: this.props.smoothRadius
});
}

//////////////////////////////////////////////////
calculatePickingColors(attribute) {
const {data} = this.props;
const {value, size} = attribute;
let i = 0;

let index = 0;
for (const object of data) {
// console.log(index)
// Use the index index instead of object.id
const pickingColor = this.encodePickingColor(index);
value[index * 3] = pickingColor[0];
value[index * 3 + 1] = pickingColor[1];
value[index * 3 + 2] = pickingColor[2];
index++;
}
}
//////////////////////////////////////////////////
}
MatrixLayer.layerName = 'MatrixLayer';
MatrixLayer.defaultProps = defaultProps;

const layer = new MatrixLayer({
id: 'matrix-layer',
data: mat_data,
getPosition: d => d.position,
getColor: d => d.color,
// getColor: d => [255, 0, 0, 50]
// required for tooltip
pickable: true,
// onHover: (info, event) => console.log('Hovered:', info, event),
});

return layer
}

Insert cell
Insert cell
row_cat_data = {

let matrix_index = 0;

var index_row = 0
const num_row_cats = 3

var num_points = num_rows * num_row_cats
return new Array(num_points).fill(0).map( _ => {

var index_col = matrix_index % num_row_cats

if (matrix_index % num_row_cats === 0){
index_row += 1;
}
const p = {
position: [row_cat_offset * index_col, row_offset * index_row],
color: [0, 255, 0, 255],
name: 'something'
};
matrix_index += 1;
return p;
});
}
Insert cell
getRowCatModel = {
const {Model, Geometry} = luma;

// required for tooltip
const {picking} = deck
return gl => {

// Four corners of the quad
const positions = new Float32Array([0, 0,
0, row_height,
row_cat_width, row_height,
row_cat_width, 0]);
const geometry = new Geometry({
drawMode: gl.TRIANGLE_FAN,
vertexCount: 4,
attributes: {
positions: {
size: 2,
value: positions
}
}
});
return new Model(gl, {
vs: vertexShader,
fs: fragmentShader,
geometry,
isInstanced: true,
// required for tooltip
modules: [picking]
});
}
}
Insert cell
cat_shift_row = 30
Insert cell
row_cat_layer = { const {Layer} = deck;
class RowLayer extends Layer {
initializeState() {
const {gl} = this.context;
// Register attributes
this.getAttributeManager().addInstanced({
instancePositions: {
size: 3,
type: gl.DOUBLE,
accessor: 'getPosition'
},
instanceColors: {
size: 4,
normalized: true,
type: gl.UNSIGNED_BYTE,
accessor: 'getColor',
defaultValue: [0, 0, 0, 255]
},
// createing a picking color attribute
customPickingColors: {
size: 3,
type: gl.UNSIGNED_BYTE,
update: this.calculatePickingColors
// update: calculatePickingColors
}
});
// Save the model in layer state
this.setState({
model: getRowCatModel(gl)
});
}
updateState() {
// Retrieve the model from layer state
this.state.model.setUniforms({
// smoothRadius: this.props.smoothRadius
});
}

//////////////////////////////////////////////////
calculatePickingColors(attribute) {
const {data} = this.props;
const {value, size} = attribute;
let i = 0;

let index = 0;
for (const object of data) {
// console.log(index)
// Use the index index instead of object.id
const pickingColor = this.encodePickingColor(index);
value[index * 3] = pickingColor[0];
value[index * 3 + 1] = pickingColor[1];
value[index * 3 + 2] = pickingColor[2];
index++;
}
}
//////////////////////////////////////////////////
}

RowLayer.layerName = 'RowLayer';
RowLayer.defaultProps = defaultProps;

const layer = new RowLayer({
id: 'row-layer',
data: row_cat_data,
// getPosition: d => d.position,
getPosition: d => [d.position[0] + cat_shift_row, d.position[1]],
getColor: d => d.color,
// required for tooltip
pickable: true,
});

return layer
}

Insert cell
Insert cell
num_cats_col = 3
Insert cell
col_cat_data = {

let matrix_index = 0;

var index_row = 0

var num_points = num_cats_col * num_cols
return new Array(num_points).fill(0).map( _ => {

var index_col = matrix_index % num_cols

if (matrix_index % num_cols === 0){
index_row += 1;
}

const p = {
position: [col_offset * index_col, col_cat_offset * index_row],
color: [0, 255, 0, 150],
name: 'some column',
};
matrix_index += 1;
return p;
});
}
Insert cell
getColCatModel = {
const {Model, Geometry} = luma;

// required for tooltip
const {picking} = deck
return gl => {

// Four corners of the quad
const positions = new Float32Array([0, 0,
0, col_cat_height,
col_width, col_cat_height,
col_width, 0]);
const geometry = new Geometry({
drawMode: gl.TRIANGLE_FAN,
vertexCount: 4,
attributes: {
positions: {
size: 2,
value: positions
}
}
});
return new Model(gl, {
vs: vertexShader,
fs: fragmentShader,
geometry,
isInstanced: true,
// required for tooltip
modules: [picking]
});
}
}
Insert cell
col_cat_layer = {
const {Layer} = deck;
class ColLayer extends Layer {
initializeState() {
const {gl} = this.context;

// Register attributes
this.getAttributeManager().addInstanced({
instancePositions: {
size: 3,
type: gl.DOUBLE,
accessor: 'getPosition'
},
instanceColors: {
size: 4,
normalized: true,
type: gl.UNSIGNED_BYTE,
accessor: 'getColor',
defaultValue: [0, 0, 0, 255]
},
// required for tooltip
customPickingColors: {
size: 3,
type: gl.UNSIGNED_BYTE,
update: this.calculatePickingColors
// update: calculatePickingColors
}
});
// Save the model in layer state
this.setState({
model: getColCatModel(gl)
});
}
updateState() {
// Retrieve the model from layer state
this.state.model.setUniforms({
// smoothRadius: this.props.smoothRadius
});
}

//////////////////////////////////////////////////
// required for tooltip
calculatePickingColors(attribute) {
const {data} = this.props;
const {value, size} = attribute;
let i = 0;

let index = 0;
for (const object of data) {
// console.log(index)
// Use the index index instead of object.id
const pickingColor = this.encodePickingColor(index);
value[index * 3] = pickingColor[0];
value[index * 3 + 1] = pickingColor[1];
value[index * 3 + 2] = pickingColor[2];
index++;
}
}
//////////////////////////////////////////////////
}
ColLayer.layerName = 'ColLayer';
ColLayer.defaultProps = defaultProps;

const layer = new ColLayer({
id: 'col-layer',
data: col_cat_data,
getPosition: d => [d.position[0], d.position[1] + cat_shift_col],
getColor: d => d.color,
// required for tooltip
pickable: true,
});

return layer
}

Insert cell
// column category positioning
cat_shift_col = col_label_height
Insert cell
Insert cell
row_label_width = 30
Insert cell
row_label_data = {

let matrix_index = 0;

var index_row = 0
// const num_row_cats = 1

var num_points = num_rows// * num_row_cats
return new Array(num_points).fill(0).map( _ => {

var index_col = matrix_index % 1 // num_row_cats

if (matrix_index % 1 == 0){ // num_row_cats =
index_row += 1;
}
const p = {
position: [row_label_width , row_offset * index_row + row_offset/2],
name: 'row-' + index_row
};
matrix_index += 1;
return p;
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

vertexShader = `

attribute vec3 positions;
attribute vec3 instancePositions;
attribute vec3 instancePositions64Low;
attribute vec4 instanceColors;

varying vec4 vColor;
varying vec2 vPosition;

attribute vec3 customPickingColors;

void main(void) {
vec3 positionCommon = project_position(instancePositions + positions , instancePositions64Low);
gl_Position = project_common_position_to_clipspace(vec4(positionCommon, 1.0));

vPosition = positions.xy;
vColor = instanceColors;

picking_setPickingColor(customPickingColors);
}

`
Insert cell
fragmentShader = `

precision highp float;

varying vec4 vColor;
varying vec2 vPosition;

void main(void) {
gl_FragColor = vec4(vColor.rgb, vColor.a);

// Should be the last Fragment shader instruction that updates gl_FragColor
gl_FragColor = picking_filterPickingColor(gl_FragColor);

}

`;


// default
/////////////////
// gl_FragColor = vec4(vColor.rgb, 1.0);

// gl_FragColor = vec4(vColor.rgb[0], vColor.rgb[1], vColor.rgb[2], vColor.rgb[3]);
// gl_FragColor = vec4(vColor.rgb, 1.0);
// gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);

// gl_FragColor = vec4(vColor.rgb, 1.0);
// gl_FragColor = vec4(255, 255, 0, 0.5);

// gl_FragColor = vec4(vColor.rgb[0], vColor.rgb[1], vColor.rgb[2], 1.0);
Insert cell
Insert cell
Insert cell
Insert cell
// layer2.getAttributeManager().getAttributes();
Insert cell
Insert cell
luma = deck && window.luma
Insert cell
Insert cell
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