Public
Edited
Apr 26, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dataDescription = ({
name: "Engine",
acknowledgement: "volvis.org and General Electric",
description: "CT scan of two cylinders of an engine block",
link: "https://klacansky.com/open-scivis-datasets/",
dataType: "uint8",
endian: "little",
scale: [1, 1, 1],
xExtent: 256,
yExtent: 256,
zExtent: 128
})
Insert cell
Insert cell
dataValues = {
const zip = await FileAttachment("engine_256x256x128_uint8.zip").zip(); // Retrieve attachment and decompress it.
const file = zip.file("engine_256x256x128_uint8.raw"); // Get the actual data file in the decompressed archive.
const buffer = await file.arrayBuffer(); // Get the byte buffer of the file.
const byteArray = new Uint8Array(buffer); // Create an uint8-array-view from the file buffer.
return byteArray; // Return the data as an uint8 array.
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function createZSliceImage(ctx, data, width, height, sliceIndex) {
// Create image buffer with the same width and height as the dataset.
// The image data has 4 channels (red, green, blue, alpha).
const image = ctx.createImageData(width, height);

// Loop through all pixels in the image and set the color based on the data.
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// Compute the data index in the 3D volume.
// The first part is the offset to the current volume slice (width * height * sliceIndex).
// The second part is the offset inside the slice to the current voxel (width * y + x).
const dataIndex = (width * height * sliceIndex) + (width * y + x);

// Get the data value.
const value = data[dataIndex];

// Compute the index of the pixel in the image data, considering the 4 color channels.
const imageIndex = (width * y + x) * 4;

// Set the pixel color.
image.data[imageIndex] = value; // Red
image.data[imageIndex + 1] = value; // Green
image.data[imageIndex + 2] = value; // Blue
image.data[imageIndex + 3] = 255; // Alpha
}
}

// Asynchronously create a bitmap from the image data (returns a promise).
return createImageBitmap(image);
}
Insert cell
Insert cell
Insert cell
async function* plotSlice(width, height, description, values, imageFn, sliceIndex) {
// Create the canvas and 2D rendering context.
const ctx = DOM.context2d(width, height);

// Create and draw the slice image. The returned bitmap image can be used
// to draw the slice image scaled to the dimensions of the canvas. The data
// aspect ratio has to be taken into account to prevent stretching of the
// slice image.
const image = await imageFn(ctx, values, description.xExtent, description.yExtent, sliceIndex);
const dataAspect = description.yExtent / description.xExtent;
ctx.drawImage(image, 0, 0, width, width * dataAspect);
// Draw the info label (current image number and overall number of images).
const info = "Image " + (sliceIndex + 1) + "/" + (description.zExtent);
ctx.font = "16px sans-serif";
drawSliceInfo(ctx, info);

// Return the canvas element.
yield ctx.canvas;
}
Insert cell
Insert cell
plotSlice(500, 500, dataDescription, dataValues, createZSliceImage, zSliceIndex)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {dataDescription as headDataDescription, dataValues as headDataValues} from "@mroehlig/3d-volume-rendering-with-webgl-three-js"
Insert cell
Insert cell
headDataDescription
Insert cell
headDataValues // Use the imported data to create and visualize a slice image...
Insert cell
Insert cell
Insert cell
viewof invertColor = Inputs.toggle({label: "Invert color", value: true})
Insert cell
Insert cell
colorScale = {
// Get a ColorBrewer color palette with the maximum available number of colors using D3.
const palette = d3.schemeRdPu[d3.schemeRdPu.length - 1];
// Create a color scale from the palette using D3. The scale function can then be used
// to retrieve interpolated color values for input values between 0 and 1.
return d3.scaleLinear()
.domain(Array.from({length: palette.length}, (_, i) => i / (palette.length - 1)))
.range(palette);
}
Insert cell
Insert cell
drawGradient(colorScale)
Insert cell
Insert cell
interpolatedColor = d3.color(colorScale(0.5))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {sliceViewer} from "@mroehlig/interactive-volume-visualization-of-2d-slices-in-x-y-and-z-plane"
Insert cell
Insert cell
sliceViewer
Insert cell
Insert cell
Insert cell
function drawSliceInfo(ctx, info) {
// Draw the info string with white color in the upper left corner.
ctx.fillStyle = "white";
ctx.fillText(info, 5, 24);
}
Insert cell
Insert cell
function* duplicateCanvas(canvas) {
// Create a new canvas and 2D rendering context with the same dimensions as the input canvas.
const ctx = DOM.context2d(canvas.clientWidth, canvas.clientHeight);
// Draw the content of the input canvas onto the new canvas.
ctx.drawImage(canvas, 0, 0, canvas.clientWidth, canvas.clientHeight);
// Return the new canvas.
yield ctx.canvas;
}
Insert cell
Insert cell
function* drawGradient(colors, n = 256) {
// Create a new canvas with it's width set to the number of colors and it's height to one.
const ctx = DOM.context2d(n, 1, 1);
// Adjust the styling of the canvas to it is displayed larger.
ctx.canvas.style.width = "100%";
ctx.canvas.style.height = "40px";
ctx.canvas.style.imageRendering = "pixelated";
// Fill the canvas's pixels based on the given color function.
for (let i = 0; i < n; ++i) {
// For each color draw a colored rectangle in the size of a pixel.
ctx.fillStyle = colors(i / (n - 1));
ctx.fillRect(i, 0, 1, 1);
}

// Return the canvas.
yield ctx.canvas;
}
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