Public
Edited
Feb 29, 2024
Importers
Insert cell
Insert cell
Insert cell
Insert cell
DEFAULT_N = 10000
Insert cell
import {
dist,
distValue,
kde,
to,
exponential,
normalInterval
} with { DEFAULT_N } from "@huw/dist"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof selfGuidedDepressionSMD = dist`${normalInterval(0.15, 0.31, {
p: 0.95
})}`
Insert cell
Insert cell
Insert cell
viewof socialDesirabilityDiscount = dist`0.7 to 0.9`
Insert cell
Insert cell
viewof publicationDiscount = dist`0.75 to 0.9`
Insert cell
Insert cell
viewof scaleDiscount = dist`0.7 to 0.85`
Insert cell
Insert cell
Insert cell
viewof effectSizeAdjustment = Inputs.range([0.1, 2.0], {
label: "Effect size adjustment",
value: 1
})
Insert cell
viewof selfGuidedDepressionSMDDiscounted = dist`${selfGuidedDepressionSMD} * ${socialDesirabilityDiscount} * ${publicationDiscount} * ${scaleDiscount} * ${effectSizeAdjustment}`
Insert cell
Insert cell
Insert cell
viewof expertLifeSatisfactionStdev = dist`(1.9 to 2.7) * 0.6 + 1.86 * 0.4`
Insert cell
Insert cell
viewof depressionToLifeSatisfaction = dist`0.7 to 1`
Insert cell
Insert cell
viewof selfGuidedWellby = dist`${selfGuidedDepressionSMDDiscounted} * ${expertLifeSatisfactionStdev} * ${depressionToLifeSatisfaction}`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof retentionAdjustment = Inputs.range([0.1, 2.0], {
label: "Retention adjustment",
value: 1
})
Insert cell
viewof mentalHealthAppRetention = dist`${exponential(
1 / 0.04
)} * ${retentionAdjustment}`
Insert cell
Insert cell
Insert cell
viewof perUserWellby = dist`${selfGuidedWellby} * ${mentalHealthAppRetention}`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof acquisitionCostAdjustment = Inputs.range([0.1, 2], { label: "CPI adjustment", value: 1 })
Insert cell
viewof marketingCostPerDownload = dist`(0.5 to 6) * ${acquisitionCostAdjustment}`
Insert cell
Insert cell
Insert cell
Insert cell
{
const data = [
{ Name: "Headspace", Employees: 1200, Downloads: 70_000_000 },
{ Name: "Calm", Employees: 400, Downloads: 135_000_000 },
{ Name: "Breeze", Employees: 20, Downloads: 2_000_000 },
{ Name: "BetterHelp", Employees: 5000, Downloads: 80_000_000 },
{ Name: "Paired", Employees: 250, Downloads: 8_000_000 },
{ Name: "Insight Timer", Employees: 350, Downloads: 10_000_000 },
{ Name: "Balance", Employees: 57, Downloads: 8_000_000 },
{ Name: "Shmoody", Employees: 5, Downloads: 1_000_000 },
{ Name: "Daylio", Employees: 5, Downloads: 20_000_000 },
{ Name: "Bearable", Employees: 7, Downloads: 600_000 }
];

return Plot.plot({
x: { type: "log", grid: true },
y: { type: "log", grid: true },
marks: [
Plot.dot(data, {
x: "Employees",
y: "Downloads",
fill: "black",
channels: { Name: "Name" },
tip: true
}),
Plot.linearRegressionY(data, { x: "Employees", y: "Downloads" })
]
});
}
Insert cell
Insert cell
viewof downloadsPerEmployee = dist`25000 to 2500000`
Insert cell
viewof employeesPerDownloadAdjustment = Inputs.range([0.1, 2], { label: "Employees per download adjustment", value: 1 })
Insert cell
viewof employeesPerDownload = dist`(1 / ${downloadsPerEmployee}) * ${employeesPerDownloadAdjustment}`
Insert cell
Insert cell
viewof costPerEmployeeAdjustment = Inputs.range([0.1, 2], {
label: "Cost per employee adjustment",
value: 1
})
Insert cell
viewof costPerEmployee = dist`(25000 to 250000) * ${costPerEmployeeAdjustment}`
Insert cell
viewof developmentCostPerDownload = dist`${employeesPerDownload} * ${costPerEmployee}`
Insert cell
Insert cell
Insert cell
viewof totalCostPerDownload = dist`(${marketingCostPerDownload} + ${developmentCostPerDownload}) * (1.1 to 1.5)`
Insert cell
Insert cell
mentalHealthAppCostEffectiveness = distValue`${perUserWellby} / ${totalCostPerDownload} * 1000`
Insert cell
Insert cell
plot = {
const density = [...kde.density1d(mentalHealthAppCostEffectiveness)];

const nearestQuantilesInDensity = [0.5]
.map((p) => d3.quantile(mentalHealthAppCostEffectiveness, p))
.map((q) => ({
i: d3.bisectCenter(
density.map((d) => d.x),
q
),
q
}))
.map(({ q, i }) => ({ x: q, y: density[i].y }));

return Plot.plot({
y: { ticks: 0, label: "Density Estimate" },
x: {
domain: [
d3.min(mentalHealthAppCostEffectiveness),
d3.max([d3.quantile(mentalHealthAppCostEffectiveness, 0.97), 70])
],
label: "Cost-Effectivess (WELLBYs/US$1000)"
},
color: { legend: true },
height: 256,
width,
marks: [
Plot.areaY(density, { x: "x", y: "y", fillOpacity: 0.1 }),
Plot.lineY(density, { x: "x", y: "y" }),
Plot.ruleY([0]),
Plot.ruleX(
[
{ Name: "GiveDirectly", "Cost-Effectiveness": 8 },
{ Name: "AMF", "Cost-Effectiveness": 70 },
{ Name: "StrongMinds", "Cost-Effectiveness": 17 }
],
{ x: "Cost-Effectiveness", stroke: "Name", tip: true }
),
Plot.ruleX(nearestQuantilesInDensity, {
x: "x",
y2: "y",
strokeDasharray: [5, 3]
}),
Plot.axisX(),
Plot.axisX(
nearestQuantilesInDensity.map(({ x }) => x),
{ textStroke: "#fff", textStrokeWidth: 5 }
),
Plot.crosshairX(density, { x: "x", y: "y" })
]
});
}
Insert cell
Insert cell
Insert cell
Insert cell
dist`${mentalHealthAppCostEffectiveness}`
Insert cell
Inputs.bind(
Inputs.range([0.1, 2], { label: "Hiring adjustment" }),
viewof employeesPerDownloadAdjustment
)
Insert cell
Insert cell
Insert cell
Inputs.bind(Inputs.range([0.1, 2], { label: "Salary adjustment" }), viewof costPerEmployeeAdjustment)
Insert cell
Insert cell
Inputs.bind(Inputs.range([0.1, 2], { label: "CPI adjustment" }), viewof acquisitionCostAdjustment)
Insert cell
Insert cell
Insert cell
Inputs.bind(
Inputs.range([0.1, 2], { label: "Retention adjustment" }),
viewof retentionAdjustment
)
Insert cell
Insert cell
Inputs.bind(
Inputs.range([0.1, 2], { label: "Effect size adjustment" }),
viewof effectSizeAdjustment
)
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