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
Plotly = await require("https://cdn.plot.ly/plotly-2.24.1.min.js")
Insert cell
viewof t_index = Scrubber(
d3.range(0, concentration[0].length),
{
autoplay: true,
delay: 100,
loop: true,
label: "Time Index (0.01sec)",
format: i => `${(i / 100).toFixed(2)} [sec]`
}
)
Insert cell
arcSegments = {
const numPoints = 80;
const maxRadius = 20;
const particleRadius = 1.1; // bubble radius at t = 0
const fadeBase = 0.45;

const total_timesteps = concentration[0].length - 1;
const growthRatio = t_index / total_timesteps;

const bubbles = [];

for (let i = 0; i < positions.length; i++) {
const [x, , z] = positions[i];
const conc = concentration[i][t_index];

const baseColor = conc > 0 ? [255, 0, 0] : [0, 0, 255];
const colorStrength = Math.abs(conc);
const fadedColor = baseColor.map(c => Math.round(255 - (255 - c) * fadeBase * colorStrength));

const radius = particleRadius + growthRatio * (maxRadius - particleRadius);

const arc = [];
for (let j = 0; j <= numPoints; j++) {
const theta = (j / numPoints) * 2 * Math.PI;
arc.push({
x: x + radius * Math.cos(theta),
z: z + radius * Math.sin(theta),
color: `rgba(${fadedColor.join(",")}, 0.3)`,
stroke: `rgb(${baseColor.join(",")})`
});
}

bubbles.push(arc);
}

return bubbles;
}

Insert cell
chart= Plotly.newPlot(
DOM.element("div", { style: "height: 400px;" }),
[
// Bubbles
...arcSegments.map(bubble => ({
type: "scatter",
mode: "lines",
x: bubble.map(p => p.x),
y: bubble.map(p => p.z),
line: {
color: bubble[0].stroke,
width: 0
},
fill: "toself",
fillcolor: bubble[0].color,
hoverinfo: "skip",
showlegend: false
})),

// Particles
{
type: "scatter",
mode: "markers",
x: positions.map(p => p[0]),
y: positions.map(p => p[2]),
marker: {
size: 16,
color: concentration.map(row => row[t_index]),
cmin: -1,
cmax: 1,
colorscale: [
[0, "blue"],
[0.5, "white"],
[1, "red"]
],
showscale: true,
colorbar: {
title: "Concentration [M]<br>positive: material I<br>negative: material II)"
},
line: { color: "black", width: 0.5 }
},
text: ["Particle 1", "Particle 2"],
hoverinfo: "text+marker.color"
}
],
{
xaxis: {
visible: false,
scaleanchor: "y"
},
yaxis: {
title: "Distance [nm]",
range: [-5,26], fixedrange: true,
//range: [
// Math.min(...positions.map(p => p[2])) - 6,
//Math.max(...positions.map(p => p[2])) + 6
},
margin: { t: 50 },
autosize: true,
dragmode: false,
showlegend: false
}
);

Insert cell
chart2 = Plotly.newPlot(
DOM.element("div", { style: "height: 400px;" }),
[
{
x: d3.range(concentration[0].length).map(d => d / 100),
y: concentration[0],
type: "scatter",
mode: "lines",
name: "Particle 1",
line: { color: "red" }
},
{
x: d3.range(concentration[1].length).map(d => d / 100),
y: concentration[1],
type: "scatter",
mode: "lines",
name: "Particle 2",
line: { color: "blue" }
},
{
x: [t_index / 100, t_index / 100],
y: [-1, 1],
type: "scatter",
mode: "lines",
name: "Current Time",
line: { dash: "dot", color: "gray" },
hoverinfo: "skip"
}
],
{
title: "Concentration vs Time",
xaxis: { title: "Time [s]" },
yaxis: { title: "Concentration [M]", range: [-1, 1] },
margin: { t: 40, r: 80 }, // 👈 Add right margin
legend: {
x: 1.02,
y: 1,
xanchor: "left",
orientation: "v"
}
}
)

Insert cell
Insert cell
Insert cell
Insert cell
fcc_bcc_data = FileAttachment("FCC_BCC_concentration.json").json()

Insert cell
viewof t_index_multi = Scrubber(
d3.range(0, fcc_bcc_data.FCC_concentration.length),
{
autoplay: true,
delay: 100,
loop: true,
label: "Time Index (0.01sec)",
format: i => `${(i / 100).toFixed(2)} [sec]`
}
)
Insert cell
concentration_BCC_1 = fcc_bcc_data.BCC_concentration.map(row => row[0]);
Insert cell
concentration_BCC_2 = fcc_bcc_data.BCC_concentration.map(row => row[1]);
Insert cell
concentration_FCC_1 = fcc_bcc_data.FCC_concentration.map(row => row[0]);
Insert cell
concentration_FCC_2 = fcc_bcc_data.FCC_concentration.map(row => row[1]);
Insert cell
viewof coloredFCC = {
const a = 1;
const n = 3;
const radius = 10;

const positions = [];
let index = 0;

for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
for (let k = 0; k < n; k++) {
const base = [i * a, j * a, k * a];
positions.push({ x: base[0], y: base[1], z: base[2], i: index++, type: "corner" });
positions.push({ x: base[0] + a/2, y: base[1] + a/2, z: base[2], i: index++, type: "face" });
positions.push({ x: base[0] + a/2, y: base[1], z: base[2] + a/2, i: index++, type: "face" });
positions.push({ x: base[0], y: base[1] + a/2, z: base[2] + a/2, i: index++, type: "face" });
}
}
}

const xs = positions.map(p => p.x);
const ys = positions.map(p => p.y);
const zs = positions.map(p => p.z);
const colors = positions.map(p =>
p.type === "corner"
? concentration_FCC_1[t_index_multi]
: concentration_FCC_2[t_index_multi]
);

const trace = {
type: "scatter3d",
mode: "markers",
x: xs,
y: ys,
z: zs,
marker: {
size: radius,
color: colors,
cmin: -1,
cmax: 1,
colorscale: [
[0, "blue"],
[0.5, "white"],
[1, "red"]
],
opacity: 1,
line: {
color: "black",
width: 0.5
},
colorbar: { title: "Concentration [M]<br>positive: material I<br>negative: material II<br>", thickness: 10 }
}
};

return Plotly.newPlot(
document.createElement("div"),
[trace],
{
scene: {
xaxis: { range: [-1, n * a + 1], visible: false },
yaxis: { range: [-1, n * a + 1], visible: false },
zaxis: { range: [-1, n * a + 1], visible: false },
aspectmode: "data",
camera: {
eye: { x: -1.06, y: -2, z: 1.5 } // angle
}
},
margin: { t: 30 },
dragmode: "turntable",
},
{
scrollZoom: false,
doubleClick: false,
displayModeBar: false
}
);
}

Insert cell
chartFCC2= Plotly.newPlot(
DOM.element("div", { style: "height: 380px;" }),
[
{
x: d3.range(concentration_FCC_1.length),
y: concentration_FCC_1,
type: "scatter",
mode: "lines",
name: "Material 1",
line: { color: "red" }
},
{
x: d3.range(concentration_FCC_2.length),
y: concentration_FCC_2,
type: "scatter",
mode: "lines",
name: "Material 2",
line: { color: "blue" }
},
{
x: [t_index_multi/100, t_index_multi/100],
y: [-1, 1],
type: "scatter",
mode: "lines",
name: "Current Time",
line: { dash: "dot", color: "gray" },
hoverinfo: "skip"
}
],
{
//title: "FCC Concentration[M] vs Time [s]",
xaxis: { title: "Time [s]" },
yaxis: { title: "Concentration [M]", range: [-1, 1] },
margin: { t: 40 }
}
)
Insert cell
Insert cell
viewof coloredBCC = {
const a = 1;
const n = 3;
const radius = 12;

const positions = [];
let index = 0;

for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
for (let k = 0; k < n; k++) {
const base = [i * a, j * a, k * a];
// 1. Corner atoms
positions.push({ x: base[0], y: base[1], z: base[2], i: index++, type: "corner" });
// 2. Body center
positions.push({ x: base[0] + a/2, y: base[1] + a/2, z: base[2] + a/2, i: index++, type: "body" });
}
}
}

const xs = positions.map(p => p.x);
const ys = positions.map(p => p.y);
const zs = positions.map(p => p.z);
const colors = positions.map(p =>
p.type === "corner"
? concentration_BCC_1[t_index_multi]
: concentration_BCC_2[t_index_multi]
);

const trace = {
type: "scatter3d",
mode: "markers",
x: xs,
y: ys,
z: zs,
marker: {
size: radius,
color: colors,
cmin: -1,
cmax: 1,
colorscale: [
[0, "blue"],
[0.5, "white"],
[1, "red"]
],
opacity: 1,
line: {
color: "black",
width: 0.5
},
colorbar: {
title: "Concentration [M]<br>positive: material I<br>negative: material II<br>",
thickness: 10
}
}
};

return Plotly.newPlot(
document.createElement("div"),
[trace],
{
scene: {
xaxis: { range: [-1, n * a + 1], visible: false },
yaxis: { range: [-1, n * a + 1], visible: false },
zaxis: { range: [-1, n * a + 1], visible: false },
aspectmode: "data",
camera: {
eye: { x: -1, y: 2, z: 1.5 }
}
},
margin: { t: 30 },
dragmode: "turntable"
},
{
scrollZoom: false,
doubleClick: false,
displayModeBar: false
}
);
}
Insert cell
chartBCC2= Plotly.newPlot(
DOM.element("div", { style: "height: 380px;" }),
[
{
x: d3.range(concentration_BCC_1.length),
y: concentration_BCC_1,
type: "scatter",
mode: "lines",
name: "Material 1",
line: { color: "red" }
},
{
x: d3.range(concentration_BCC_2.length),
y: concentration_BCC_2,
type: "scatter",
mode: "lines",
name: "Material 2",
line: { color: "blue" }
},
{
x: [t_index_multi/100, t_index_multi/100],
y: [-1, 1],
type: "scatter",
mode: "lines",
name: "Current Time",
line: { dash: "dot", color: "gray" },
hoverinfo: "skip"
}
],
{
//title: "BCC Concentration vs Time[s]",
xaxis: { title: "Time [s]" },
yaxis: { title: "Concentration [M]", range: [-1, 1] },
margin: { t: 40 }
}
)
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