Public
Edited
Sep 14, 2023
Insert cell
Insert cell
Insert cell
lenses = [35, 50, 85, 100, 120, 150]
Insert cell
Insert cell
distances_ft = [2, 4, 6, 8, 10, 12, 14]
Insert cell
distances_mm = distances_ft.map(ft2mm)
Insert cell
Insert cell
DoF = function(lens, fstop, distance) {
return farPoint(lens, fstop, distance) - nearPoint(lens, fstop, distance)
}
Insert cell
hyperFocal = function(lens, fstop) {
return lens + ((Math.pow(lens, 2)) / (fstop * CoC))
}
Insert cell
nearPoint = function(lens, fstop, distance) {
return (hyperFocal(lens, fstop) * distance) / (hyperFocal(lens, fstop) + distance - lens)
}
Insert cell
farPoint = function(lens, fstop, distance) {
return (hyperFocal(lens, fstop) * distance) / (hyperFocal(lens, fstop) - distance - lens)
}
Insert cell
Insert cell
Insert cell
mm2ft = function(mm) { return mm / 304.8 }
Insert cell
Insert cell
Insert cell
dof_data = function() {
var data = [];

_.each(lenses, function(lens) {
_.each(fstops, function(fstop) {
_.each(distances_mm, function(d, i) {
var df = mm2ft(DoF(lens, fstop, d));
if (df > 5) { df = 5 }
if (df < 0) { df = 0 }
data.push({
"lens": lens,
"fstop": fstop,
"lens_fstop": lens + "mm @ f" + fstop,
"distance_mm": d,
"distance_ft": distances_ft[i],
"dof": df,
"nearPoint": mm2ft(nearPoint(lens, fstop, d)),
"farPoint": mm2ft(farPoint(lens, fstop, d)),
"hyperFocal": mm2ft(hyperFocal(lens, fstop, d)),
"x1": 0 - (df / 2),
"x2": (df / 2)
})
})
})
});

return data;
}();
Insert cell
Insert cell
Plot.plot({
title: "Depth of Field by Lens, Object Distance and fStop",
subtitle: "How much of an object will be in focus given a lens/fstop at a specific distance?",
color: { legend: true },
x: { grid: false, domain: [2.8, 4, 5.6, 8, 11, 16], label: "fStop" },
fx: { grid: false, label: "Lens", tickFormat: (t) => (t + " mm") },
y: { grid: true, domain: [0, 20], label: "Distance", tickFormat: (t) => (t + "'")},
fy: {label: "Object Distance", tickFormat: (t) => (t + " ft")},
width: 1200,
height: 2000,
marks: [
Plot.frame({ strokeOpacity: 0.1 }),

Plot.ruleX(dof_data, {
fy: yfacet,
y1: "nearPoint",
y2: (d) => (_.clamp(d["farPoint"], 0, 20)),
x: "fstop",
fx: xfacet,
//dx: (d) => (10 * _.indexOf([2.8, 4.0, 8.0, 11.0, 16.0], d["fstop"])),
sort: (d) => (d["fstop"] * -1),
stroke: function(d) {
if(d["dof"] < 1.5) {
return "#999999"
} else if(d["dof"] < 3) {
return "#F59E0B"
} else if(d["dof"] < 4) {
return "#22C55E"
} else if(d["dof"] < 5) {
return "#16A34A"
} else {
return "#166534"
}
},
fillOpacity: 0.3,
//stroke: "#333333",
strokeWidth: 20,
tip: true,
}),

Plot.ruleY(dof_data, {
fy: yfacet,
x1: 2.8,
x2: 16,
y: "distance_ft",
fx: xfacet,
stroke: "red",
strokeWidth: 1,
//strokeWidth: 30,
//strokeOpacity: 0.05,
dx: -10
}),

Plot.text(dof_data, {
fy: yfacet,
x: "fstop",
y: "nearPoint",
fx: xfacet,
text: (d) => ("f" + d["fstop"]),
fill: "black",
dy: 10,
//textAnchor: "bottom"
}),

Plot.text(dof_data, {
fy: yfacet,
x: "fstop",
y: (d) => (d["nearPoint"] + (_.clamp(d["farPoint"], 0, 20) - d["nearPoint"]) / 2),
fx: xfacet,
text: (d) => (d["dof"] === 5 ? ">5" : _.round(d["dof"], 1)),
fill: "white",
//dx: -10,
//textAnchor: "bottom"
}),

Plot.ruleY([0])
]
})
Insert cell
yfacet = "distance_ft"
Insert cell
xfacet = "lens";
Insert cell
Plot.plot({
title: "Depth of field by lens and fstop",
subtitle: "What is the depth of field for each lens/fstop for objects at different distances?",
color: { legend: true },
x: { grid: true },
y: { grid: true, reverse: true },
width: 1200,
marks: [
Plot.frame({ strokeOpacity: 0.1 }),

Plot.barX(dof_data, {
fy: "lens",
//x1: "nearPoint",
//x2: "farPoint",
x1: "x1",
x2: "x2",
y: "distance_ft",
fx: "fstop",
fill: (d) => (d["dof"] > 1.5 ? "green" : "#999999"),
tip: true,
}),

Plot.text(dof_data, {
fy: "lens",
//x1: "nearPoint",
//x2: "farPoint",
x: 0,
y: "distance_ft",
fx: "fstop",
text: (d) => (d["distance_ft"] + ": " + _.round(d["dof"], 1)),
fill: "white"
}),
Plot.ruleY([0])
]
})
Insert cell
Plot.plot({
title: "Depth of field by lens and fstop",
subtitle: "What is the depth of field for each lens/fstop for objects at different distances?",
color: { legend: true },
marginLeft: 100,
x: { grid: true },
y: { grid: true, domain: lens_fstop_domain},
height: 3000,
marks: [
Plot.frame({ strokeOpacity: 0.1 }),

Plot.barX(dof_data, {
y: "lens_fstop",
fy: "distance_ft",
x: "dof",
fill: (d) => (d["dof"] > 1.5 ? "green" : "#cccccc"),
tip: true,
sort: "lens_fstop"
}),

/*
Plot.text(dof_data, {
fy: "lens",
//x1: "nearPoint",
//x2: "farPoint",
x: 0,
y: "distance_ft",
fx: "fstop",
text: (d) => (d["distance_ft"] + ": " + _.round(d["dof"], 1)),
fill: "white"
}),
*/
Plot.ruleY([0])
]
})
Insert cell
lens_fstop_domain = _.reduce(dof_data, function(items, i) {
if(_.indexOf(items, i.lens_fstop) == -1) {
items.push(i.lens_fstop)
}

return items
}, [])
Insert cell
Plot.plot({
title: "Depth of field by lens and fstop",
subtitle: "What is the depth of field for each lens/fstop for objects at different distances?",
color: { legend: true },
marginLeft: 100,
x: { grid: true, domain: [0, 20]},
y: { grid: true, domain: lens_fstop_domain},
height: 3000,
marks: [
Plot.frame({ strokeOpacity: 0.1 }),

Plot.barX(dof_data, {
y: "lens_fstop",
fy: "distance_ft",
x1: "nearPoint",
x2: (d) => (_.clamp(d["farPoint"], 0, 20)),
fill: (d) => (d["dof"] > 1.5 ? "green" : "#cccccc"),
tip: true
}),

Plot.ruleX(dof_data, {
//y1: _.first(lens_fstop_domain),
//y2: _.last(lens_fstop_domain),
fy: "distance_ft",
x: "distance_ft",
stroke: "red",
strokeWidth: 1
}),

Plot.text(dof_data, {
fy: "distance_ft",
y: "lens_fstop",
x: "nearPoint",
text: (d) => (_.round(d["dof"], 1)),
dx: -10
//fill: "white"
}),
Plot.ruleY([0])
]
})
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