Public
Edited
Dec 1, 2022
Importers
Insert cell
Insert cell
Insert cell
function render_binary_mask(ctx, array, color_fg="white", opacity_fg=1.0, color_bg="black", opacity_bg=0.0){
const [nrows, ncols] = [ctx.canvas.height, ctx.canvas.width];
let val, color;
for(let r=0; r<nrows; r++){
for(let c=0; c<ncols; c++){
val = Math.round(array[r][c]);
if(val == 1){
color = d3.color(color_fg);
color.opacity = opacity_fg;
}else if(val == 0){
color = d3.color(color_bg);
color.opacity = opacity_bg;
}
ctx.fillStyle = color;
ctx.fillRect(c, r, 1, 1);
}
}
}
Insert cell
function render_image(ctx, array, cmap, reversed=false, zero_transparency=false){
// array is a 2D array with rows (h) in the first dim and cols (w) in the second
// cmap is a d3 interpolator function that gets a number and returns a 4 number array representing an rgba color
// TODO: see if there is a more efficient way to draw pixels in canvas
const [nrows, ncols] = [ctx.canvas.height, ctx.canvas.width];
const min = Math.min(...array.map(d => Math.min(...d)));
const max = Math.max(...array.map(d => Math.max(...d)));
const interpolator = d3.scaleSequential().interpolator(cmap);
if(reversed){
interpolator.domain([max, min]);
}else{
interpolator.domain([min, max]);
}
let val;
for(let r=0; r<nrows; r++){
for(let c=0; c<ncols; c++){
val = d3.color(interpolator(array[r][c]));
if(zero_transparency && array[r][c] === min){
val.opacity = 0.0;
}
ctx.fillStyle = val;
ctx.fillRect(c, r, 1, 1);
}
}
}
Insert cell
function threshold_contour_sdf(sdf_array, level, bg_fg=[0.0, 1.0]){
let contour = [];
sdf_array.forEach(c => {
let col = [];
c.forEach(re => {
if(re > level){
col.push(bg_fg[1]);
}else{
col.push(bg_fg[0]);
}
});
contour.push(col);
})
return contour;
}
Insert cell
Insert cell
function plot_isocurve(ctx, array, isolevel=0.5, line_params={}){

const w = ctx.canvas.width;
const h = ctx.canvas.height;

if(!("color" in line_params))
line_params.color = "red";
if(!("opacity" in line_params))
line_params.opacity = 1.0;
if(!("width" in line_params))
line_params.width = 1.0;
if(!("dash_pattern" in line_params))
line_params.dash_pattern = [];
// Plot contour as path
const array_flat = flatten(array);
const contour_extractor = d3.contours().size([h, w]);
const contour_geo_path = contour_extractor.contour(array_flat, isolevel);

let color = d3.color(line_params.color);
color.opacity = line_params.opacity;
ctx.strokeStyle = color;
ctx.lineWidth = line_params.width;
ctx.setLineDash(line_params.dash_pattern);

const path = d3.geoPath().context(ctx);
ctx.beginPath();
path(contour_geo_path);
ctx.stroke();
return line_params;
}
Insert cell
Insert cell
function flatten(array, order="row_major"){
const out = [];
const nrows = array.length;
const ncols = array[0].length;
const data_length = nrows * ncols;
let row_idx, col_idx, val;

if(order === "row_major"){
for(let i=0; i<data_length; i++){
row_idx = parseInt(i / ncols);
col_idx = i % ncols;
val = array[row_idx][col_idx];
out.push(val);
}
}else if(order === "col_major"){
for(let i=0; i<data_length; i++){
col_idx = parseInt(i / nrows);
row_idx = i % nrows;
val = array[row_idx][col_idx];
out.push(val);
}
}
return out;
}
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