Notebooks 2.0 is here.
Read the preview announcement
Platform
Resources
Pricing
Sign in
Get started
Martin Röhlig
Workspace
Fork
Public
Visualization Tutorial
By
Martin Röhlig
Edited
Jun 8, 2023
3 forks
2 stars
Visualization Tutorial
Visualization of 2D slices through a 3D volume dataset (exercise)
Visualization of 2D slices through a 3D volume dataset (solution)
3D volume rendering with WebGL / Three.js (exercise)
3D volume rendering with WebGL / Three.js (solution)
Flow visualization of a 2D vector field with arrow glyphs and particle simulation (exercise)
Flow visualization of a 2D vector field with arrow glyphs and particle simulation (solution)
Visualization of univariate data with D3 (exercise)
Visualization of univariate data with D3 (solution)
Visualization of multivariate data with D3 — Colored Table (exercise)
Visualization of multivariate data with D3 — Colored Table (solution)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
fields
=
new
Map
(
[
[
"left to right"
,
(
x
,
y
)
=>
[
x
,
0
]
]
,
// Horizontal flow from left to right.
[
"diagonal"
,
(
x
,
y
)
=>
[
x
,
x
]
]
,
// Diagonal flow from top-left to bottom-right.
[
"circle"
,
(
x
,
y
)
=>
[
y
-
0.5
,
0.5
-
x
]
]
,
// Circular flow.
[
"repel"
,
(
x
,
y
)
=>
[
x
-
0.5
,
y
-
0.5
]
]
,
// Repelling flow from the center.
]
)
Insert cell
Insert cell
exampleVector
=
fields
.
get
(
"left to right"
)
(
0.5
,
0.5
)
// Sample the field.
Insert cell
Insert cell
Insert cell
Insert cell
function
dirToColor
(
dir
)
{
// Normalize the vector (value range from -1 to 1).
const
normal
=
getNormalized
(
dir
)
;
// Map values to be between 0 and 1.
normal
[
0
]
=
(
normal
[
0
]
+
1
)
*
0.5
;
normal
[
1
]
=
(
normal
[
1
]
+
1
)
*
0.5
;
// Convert to array of color values.
return
[
Math
.
floor
(
normal
[
0
]
*
255
)
,
Math
.
floor
(
normal
[
1
]
*
255
)
,
0
,
255
]
;
}
Insert cell
mutable
animatedVector
=
[
0
,
0
]
;
// Example vector (same as in the animation above).
Insert cell
animatedVectorColor
=
dirToColor
(
animatedVector
)
// Animated vector converted to color.
Insert cell
Insert cell
async
function
createImage
(
ctx
,
width
,
height
,
field
,
alphaScale
=
1.0
)
{
// Create the image data.
let
image
=
ctx
.
createImageData
(
width
,
height
)
;
// Loop through the image pixels.
for
(
let
y
=
0
,
i
=
0
;
y
<
height
;
y
++
)
{
// Convert pixel-y to field-y (value between 0 and 1).
const
fy
=
y
/
(
height
-
1
)
;
for
(
let
x
=
0
;
x
<
width
;
x
++
,
i
+=
4
)
{
// Convert pixel-x to field-x (value between 0 and 1).
const
fx
=
x
/
(
width
-
1
)
;
// Retrieve the vector from the field for the current pixel.
const
dir
=
field
(
fx
,
fy
)
;
// Convert the vector to a color.
const
color
=
dirToColor
(
dir
)
;
// Assign the color values to the pixel color.
image
.
data
[
i
]
=
color
[
0
]
;
// Red
image
.
data
[
i
+
1
]
=
color
[
1
]
;
// Green
image
.
data
[
i
+
2
]
=
color
[
2
]
;
// Blue
image
.
data
[
i
+
3
]
=
color
[
3
]
*
alphaScale
;
// Alpha
}
}
// Create and return a bitmap image from the image data.
return
createImageBitmap
(
image
)
;
}
Insert cell
Insert cell
{
// Create a canvas.
const
size
=
Math
.
min
(
width
,
450
)
;
const
ctx
=
DOM
.
context2d
(
size
,
size
)
;
ctx
.
canvas
.
style
.
border
=
"solid 1px black"
;
// Get a field.
const
field
=
fields
.
get
(
"circle"
)
;
// Create and draw the image.
const
image
=
await
createImage
(
ctx
,
size
,
size
,
field
)
;
ctx
.
drawImage
(
image
,
0
,
0
,
size
,
size
)
;
// Return the canvas.
return
ctx
.
canvas
;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function
drawArrow
(
ctx
,
cx
,
cy
,
dir
,
size
,
lineWidth
=
1
,
strokeColor
=
"#000"
)
{
// Calculate arrow properties.
const
mag
=
getMagnitute
(
dir
)
;
const
normal
=
getNormalized
(
dir
)
;
const
angle
=
Math
.
atan2
(
dir
[
1
]
,
dir
[
0
]
)
;
// Use the vector magnitude to scale the length of the arrow.
const
length
=
Math
.
max
(
1
,
size
*
mag
)
;
// Calculate start and end position of arrow.
const
x0
=
cx
-
normal
[
0
]
*
length
;
const
y0
=
cy
-
normal
[
1
]
*
length
;
const
x1
=
cx
+
normal
[
0
]
*
length
;
const
y1
=
cy
+
normal
[
1
]
*
length
;
// Set the render properties.
ctx
.
strokeStyle
=
strokeColor
;
ctx
.
lineWidth
=
lineWidth
;
ctx
.
lineCap
=
"round"
;
ctx
.
beginPath
(
)
;
// Set the center line of the arrow.
ctx
.
moveTo
(
x0
,
y0
)
;
ctx
.
lineTo
(
x1
,
y1
)
;
// Set the lines of the arrow head.
ctx
.
moveTo
(
x1
,
y1
)
;
ctx
.
lineTo
(
x1
-
length
*
Math
.
cos
(
angle
-
Math
.
PI
/
6
)
,
y1
-
length
*
Math
.
sin
(
angle
-
Math
.
PI
/
6
)
)
;
ctx
.
moveTo
(
x1
,
y1
)
;
ctx
.
lineTo
(
x1
-
length
*
Math
.
cos
(
angle
+
Math
.
PI
/
6
)
,
y1
-
length
*
Math
.
sin
(
angle
+
Math
.
PI
/
6
)
)
;
// Draw the arrow.
ctx
.
stroke
(
)
;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function
createParticle
(
x
,
y
,
size
=
3
,
time
=
20
,
color
=
"#a6cee3"
)
{
// Return a particle object that stores the particle positions and its properties.
return
{
x
:
x
,
y
:
y
,
size
:
size
,
color
:
color
,
time
:
time
}
}
Insert cell
Insert cell
function
createParticles
(
count
=
particleProps
.
count
,
size
=
particleProps
.
size
,
time
=
particleProps
.
lifetime
)
{
// Create an array of particles with random positions.
let
particles
=
[
]
;
for
(
let
i
=
0
;
i
<
count
;
++
i
)
{
particles
.
push
(
createParticle
(
Math
.
random
(
)
,
Math
.
random
(
)
,
size
,
time
)
)
;
}
return
particles
;
}
Insert cell
Insert cell
function
updateParticle
(
particle
,
field
,
dt
=
1
,
speed
=
0.01
)
{
// Get the particle's x and y coordinate.
let
{
x
,
y
}
=
particle
;
// Lower the particle's lifetime based on the elapsed time.
particle
.
time
-=
dt
;
// Check if the particle is inside boundaries and alive.
if
(
x
>=
0
&&
x
<=
1
&&
y
>=
0
&&
y
<=
1
&&
particle
.
time
>
0
)
{
// Sample the field at the current particle position.
const
dir
=
field
(
x
,
y
)
;
// Move the particle based on the sampled field vector, scaled by the elapsed time and velocity factor.
particle
.
x
=
x
+
dir
[
0
]
*
dt
*
speed
;
particle
.
y
=
y
+
dir
[
1
]
*
dt
*
speed
;
}
else
{
// Reset the particle (outside boundary or beyond lifetime).
resetParticle
(
particle
)
;
}
}
Insert cell
Insert cell
function
resetParticle
(
particle
,
time
=
particleProps
.
lifetime
)
{
// Reset the particle position.
particle
.
x
=
Math
.
random
(
)
;
particle
.
y
=
Math
.
random
(
)
;
// Reset the particle lifetime.
particle
.
time
=
time
;
}
Insert cell
Insert cell
function
drawParticle
(
ctx
,
particle
)
{
// Get the width and height of the canvas.
const
width
=
ctx
.
canvas
.
width
/
window
.
devicePixelRatio
;
const
height
=
ctx
.
canvas
.
height
/
window
.
devicePixelRatio
;
// Construct a circle to represent the particle.
ctx
.
beginPath
(
)
;
ctx
.
arc
(
particle
.
x
*
width
,
// Convert x to canvas coordinates.
particle
.
y
*
height
,
// Convert y to canvas coordinates.
particle
.
size
,
0
,
2
*
Math
.
PI
)
;
// Fill the circle.
ctx
.
fillStyle
=
particle
.
color
;
ctx
.
fill
(
)
;
// Draw the circle outline.
ctx
.
strokeStyle
=
"#333333"
;
ctx
.
stroke
(
)
;
}
Insert cell
Insert cell
{
await
visibility
(
)
;
// Create a canvas.
const
size
=
Math
.
min
(
width
,
350
)
;
const
ctx
=
DOM
.
context2d
(
size
,
size
)
;
ctx
.
canvas
.
style
.
border
=
"solid 1px black"
;
// Get a field and create a background image.
const
field
=
fields
.
get
(
"repel"
)
;
const
image
=
await
createImage
(
ctx
,
size
,
size
,
field
)
;
// Create the particles.
const
particles
=
createParticles
(
15
)
;
// Animation loop.
let
time
=
performance
.
now
(
)
;
while
(
true
)
{
// Clear the canvas.
ctx
.
clearRect
(
0
,
0
,
size
,
size
)
;
// Draw the background image.
ctx
.
drawImage
(
image
,
0
,
0
,
size
,
size
)
;
// Calculate the time delta.
const
now
=
performance
.
now
(
)
;
const
dt
=
(
now
-
time
)
/
1000
;
time
=
now
;
// Update and draw the particles.
particles
.
forEach
(
(
particle
)
=>
{
updateParticle
(
particle
,
field
,
dt
,
100
/
size
)
;
drawParticle
(
ctx
,
particle
)
;
}
)
;
// Return the canvas.
yield
ctx
.
canvas
;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
particles
=
createParticles
(
particleProps
.
count
,
particleProps
.
size
,
particleProps
.
lifetime
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import
{
flowVis
}
from
"@mroehlig/flow-visualization-of-2d-vector-fields-solution"
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.
Try it for free
Learn more
Fork
View
Export
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
fields
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
exampleVector
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
dirToColor
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
animatedVector
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
animatedVectorColor
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
createImage
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
fieldTypesCanvas
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
drawArrow
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
createParticle
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
createParticles
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
updateParticle
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
resetParticle
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
drawParticle
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
fieldProps
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
arrowProps
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
particleProps
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
particleReset
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
particles
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
getMagnitute
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
getNormalized
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
addVector
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
scaleVector
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
interpolateVector
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
lerp
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
negateVector
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
rgbToHex
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
numberToHex
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
duplicateCanvas
Edit
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Edit
Add comment
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML
Add comment
Copy import
Select
Duplicate
Copy link
Embed
Delete
JavaScript
Markdown
HTML