Public
Edited
Dec 21, 2022
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
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
{
const plt = Plot.plot({
width: width * 0.5,
height: height * 0.5,
y: {
grid: true
// tickFormat: "+f",
// label: "↑ b2"
},
x: {
grid: true
},
color: {
scheme: palette,
legend: true
},
marks: [
Plot.ruleY([1.0]),
Plot.ruleX([0]),
Plot.line(data, {
x: "valuePN",
y: "b2",
stroke: "s2"
})
]
});

document.getElementById("div1").innerHTML = plt.outerHTML;
return 'Plot into div1'
// return plt;
}
Insert cell
{
const plt = Plot.plot({
width: width * 0.5,
height: height * 0.5,
y: {
grid: true
// tickFormat: "+f",
// label: "↑ b2"
},
x: {
grid: true
},
color: {
scheme: palette,
legend: true
},
marks: [
Plot.ruleX([100]),
Plot.ruleY([0]),
Plot.line(data, {
x: "s2",
y: "valuePN",
stroke: "b2"
})
]
});
document.getElementById("div2").innerHTML = plt.outerHTML;
return "Plot into div2";
}
Insert cell
d3.extent(dataContours, (d) => d.value)
Insert cell
dataContours = {
return d3
.contourDensity()
.x((d) => x(d.s2))
.y((d) => y(d.b2))
.weight((d) => d.value)
.size([width, height])
.bandwidth(30)
.thresholds(30)(data);
}
Insert cell
x = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.s2))
.nice()
.rangeRound([0, width])
Insert cell
y = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.b2))
.nice()
.rangeRound([height, 0])
Insert cell
xAxis = g => g.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("y", -3)
.attr("dy", null)
.attr("font-weight", "bold")
.text(data.x))
Insert cell
yAxis = g => g.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickSizeOuter(0))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
Insert cell
height = parseInt(width * 0.5)
Insert cell
margin = ({ top: 20, right: 30, bottom: 30, left: 40 })
Insert cell
colorMap = (value) => {
const cs = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.value))
.range([0, 1]);
return d3[`interpolate${palette}`](cs(value));
}
Insert cell
data = {
const data = [],
n = simulations;

var s1 = 100,
s2,
b1 = 1,
b2,
a = 2,
res;

const rs2 = d3.randomUniform(s1 / s2Factor, s1 * s2Factor),
rb2 = d3.randomUniform(b1 / b2Factor, b1 * b2Factor);

if (gridMode) {
const n = Math.sqrt(simulations),
m = (n / width) * height,
is = d3
.scaleLinear()
.domain([0, n])
.range([s1 / s2Factor, s1 * s2Factor]),
js = d3
.scaleLinear()
.domain([0, m])
.range([b1 / b2Factor, b1 * b2Factor]);

for (let i = 0; i < n; ++i) {
for (let j = 0; j < m; ++j) {
s2 = is(i);
b2 = js(j);
res = simulateBattle(s1, s2, b1, b2, a);
data.push({
s1,
s2,
b1,
b2,
a,
winner: res[0],
value: res[1]
});
}
}
} else {
for (let i = 0; i < n; ++i) {
s2 = rs2();
b2 = rb2();
res = simulateBattle(s1, s2, b1, b2, a);
data.push({
s1,
s2,
b1,
b2,
a,
winner: res[0],
value: res[1]
});
}
}

data.map((d) => (d.valuePN = d.winner === "force 2" ? d.value : -d.value));

return data;
}
Insert cell
simulateBattle(100, 200, 2, 1, 2)
Insert cell
simulateBattle = (s1, s2, b1, b2, a) => {
// Initialize the size of each force
let size1 = s1;
let size2 = s2;

// Simulate the battle until one side loses
while (size1 > 0 && size2 > 0) {
// Calculate the relative strength of each force
let strength1 = Math.pow(b1 / b2, 1 / a);
let strength2 = Math.pow(b2 / b1, 1 / a);

// Calculate the number of units lost by each force
let loss1 = strength2 * size2;
let loss2 = strength1 * size1;

// Update the size of each force
size1 -= loss1;
size2 -= loss2;
}

// Return the winner and the final size of each force
if (size1 <= 0 && size2 > 0) {
return ["force 2", size2];
} else if (size2 <= 0 && size1 > 0) {
return ["force 1", size1];
} else {
return ["tie", 0];
}
}
Insert cell
It says:

Sure! The Lanchester function is a mathematical model that describes the relationship between the size of two opposing forces and their relative strength. The function takes the form of:

S1 / S2 = (B1 / B2) ^ (1/a)

Where:

- S1 is the size of force 1
- S2 is the size of force 2
- B1 is the strength of force 1
- B2 is the strength of force 2
- a is a constant that represents the relative efficiency of the two forces

Here is a JavaScript function that demonstrates the Lanchester function:

```javascript
function simulateBattle(s1, s2, b1, b2, a) {
// Initialize the size of each force
let size1 = s1;
let size2 = s2;

// Simulate the battle until one side loses
while (size1 > 0 && size2 > 0) {
// Calculate the relative strength of each force
let strength1 = Math.pow(b1 / b2, 1 / a);
let strength2 = Math.pow(b2 / b1, 1 / a);

// Calculate the number of units lost by each force
let loss1 = strength2 * size2;
let loss2 = strength1 * size1;

// Update the size of each force
size1 -= loss1;
size2 -= loss2;
}

// Return the winner and the final size of each force
if (size1 <= 0 && size2 > 0) {
return ["force 2", size2];
} else if (size2 <= 0 && size1 > 0) {
return ["force 1", size1];
} else {
return ["tie", 0];
}
}

// Example usage:
console.log(simulateBattle(100, 200, 2, 1, 2)); // Outputs: ["force 2", 100]

```

Insert cell
palettes = [
"RdBu",
"PuOr",
"Viridis",
"Inferno",
"Turbo",
"Magma",
"Plasma",
"Cividis",
"Warm",
"Cool",
"CubehelixDefault",
"BuPu",
"BuGn",
"GnBu",
"PuBu",
"PuRd",
"RdPu",
"PuBuGn",
"OrRd",
"YlGnBu",
"YlGn",
"YlOrRd",
"YlOrBr"
]
Insert cell
d3 = require("d3")
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